home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 24 / CU Amiga Magazine's Super CD-ROM 24 (1998)(EMAP Images)(GB)(Track 1 of 2)[!][issue 1998-07].iso / CUCD / Utilities / vim-5.1 / src / misc1.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-03-23  |  101.7 KB  |  4,478 lines

  1. /* vi:set ts=8 sts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved    by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  */
  8.  
  9. /*
  10.  * misc1.c: functions that didn't seem to fit elsewhere
  11.  */
  12.  
  13. #include "vim.h"
  14.  
  15. #ifdef HAVE_FCNTL_H
  16. # include <fcntl.h>        /* for chdir() */
  17. #endif
  18.  
  19. static int get_indent_str __ARGS((char_u *ptr));
  20.  
  21. /*
  22.  * count the size of the indent in the current line
  23.  */
  24.     int
  25. get_indent()
  26. {
  27.     return get_indent_str(ml_get_curline());
  28. }
  29.  
  30. /*
  31.  * count the size of the indent in line "lnum"
  32.  */
  33.     int
  34. get_indent_lnum(lnum)
  35.     linenr_t    lnum;
  36. {
  37.     return get_indent_str(ml_get(lnum));
  38. }
  39.  
  40. /*
  41.  * count the size of the indent in line "ptr"
  42.  */
  43.     static int
  44. get_indent_str(ptr)
  45.     char_u  *ptr;
  46. {
  47.     int        count = 0;
  48.  
  49.     for ( ; *ptr; ++ptr)
  50.     {
  51.     if (*ptr == TAB)    /* count a tab for what it is worth */
  52.         count += (int)curbuf->b_p_ts - (count % (int)curbuf->b_p_ts);
  53.     else if (*ptr == ' ')
  54.         ++count;        /* count a space for one */
  55.     else
  56.         break;
  57.     }
  58.     return (count);
  59. }
  60.  
  61. /*
  62.  * set the indent of the current line
  63.  * leaves the cursor on the first non-blank in the line
  64.  */
  65.     void
  66. set_indent(size, del_first)
  67.     int        size;
  68.     int        del_first;
  69. {
  70.     int        oldstate = State;
  71.     int        c;
  72. #ifdef RIGHTLEFT
  73.     int        old_p_ri = p_ri;
  74.  
  75.     p_ri = 0;                /* don't want revins in ident */
  76. #endif
  77.  
  78.     State = INSERT;            /* don't want REPLACE for State */
  79.     curwin->w_cursor.col = 0;
  80.     if (del_first)            /* delete old indent */
  81.     {
  82.                     /* vim_iswhite() is a define! */
  83.     while ((c = gchar_cursor()), vim_iswhite(c))
  84.         (void)del_char(FALSE);
  85.     }
  86.     if (!curbuf->b_p_et)        /* if 'expandtab' is set, don't use TABs */
  87.     while (size >= (int)curbuf->b_p_ts)
  88.     {
  89.         ins_char(TAB);
  90.         size -= (int)curbuf->b_p_ts;
  91.     }
  92.     while (size)
  93.     {
  94.     ins_char(' ');
  95.     --size;
  96.     }
  97.     State = oldstate;
  98. #ifdef RIGHTLEFT
  99.     p_ri = old_p_ri;
  100. #endif
  101. }
  102.  
  103. #if defined(CINDENT) || defined(SMARTINDENT)
  104.  
  105. static int cin_is_cinword __ARGS((char_u *line));
  106.  
  107. /*
  108.  * Return TRUE if the string "line" starts with a word from 'cinwords'.
  109.  */
  110.     static int
  111. cin_is_cinword(line)
  112.     char_u    *line;
  113. {
  114.     char_u  *cinw;
  115.     char_u  *cinw_buf;
  116.     int        cinw_len;
  117.     int        retval = FALSE;
  118.     int        len;
  119.  
  120.     cinw_len = STRLEN(curbuf->b_p_cinw) + 1;
  121.     cinw_buf = alloc((unsigned)cinw_len);
  122.     if (cinw_buf != NULL)
  123.     {
  124.     line = skipwhite(line);
  125.     for (cinw = curbuf->b_p_cinw; *cinw; )
  126.     {
  127.         len = copy_option_part(&cinw, cinw_buf, cinw_len, ",");
  128.         if (STRNCMP(line, cinw_buf, len) == 0 &&
  129.              (!vim_iswordc(line[len]) || !vim_iswordc(line[len - 1])))
  130.         {
  131.         retval = TRUE;
  132.         break;
  133.         }
  134.     }
  135.     vim_free(cinw_buf);
  136.     }
  137.     return retval;
  138. }
  139. #endif
  140.  
  141. /*
  142.  * open_line: Add a new line below or above the current line.
  143.  *
  144.  * Caller must take care of undo.
  145.  *
  146.  * Return TRUE for success, FALSE for failure
  147.  */
  148.     int
  149. open_line(dir, redraw, del_spaces, old_indent)
  150.     int        dir;        /* FORWARD or BACKWARD */
  151.     int        redraw;        /* > 0: redraw afterwards, < 0: insert lines*/
  152.     int        del_spaces;    /* delete spaces after cursor */
  153.     int        old_indent;    /* indent for after ^^D in Insert mode */
  154. {
  155.     char_u  *saved_line;    /* copy of the original line */
  156.     char_u  *p_extra = NULL;    /* what goes to next line */
  157.     int        extra_len = 0;    /* length of p_extra string */
  158.     FPOS    old_cursor;        /* old cursor position */
  159.     int        newcol = 0;        /* new cursor column */
  160.     int        newindent = 0;    /* auto-indent of the new line */
  161.     int        n;
  162.     int        trunc_line = FALSE;    /* truncate current line afterwards */
  163.     int        retval = FALSE;    /* return value, default is FAIL */
  164.     int        lead_len;        /* length of comment leader */
  165.     char_u  *lead_flags;    /* position in 'comments' for comment leader */
  166.     char_u  *leader = NULL;    /* copy of comment leader */
  167.     char_u  *allocated = NULL;    /* allocated memory */
  168.     char_u  *p;
  169.     int        saved_char = NUL;    /* init for GCC */
  170.     FPOS    *pos;
  171.     int        old_plines = 0;    /* init for GCC */
  172.     int        new_plines = 0;    /* init for GCC */
  173. #ifdef SMARTINDENT
  174.     int        no_si = FALSE;    /* reset did_si afterwards */
  175.     int        first_char = NUL;    /* init for GCC */
  176. #endif
  177.  
  178.     /*
  179.      * make a copy of the current line so we can mess with it
  180.      */
  181.     saved_line = vim_strsave(ml_get_curline());
  182.     if (saved_line == NULL)        /* out of memory! */
  183.     return FALSE;
  184.  
  185.     if (State == INSERT || State == REPLACE)
  186.     {
  187.     p_extra = saved_line + curwin->w_cursor.col;
  188. #ifdef SMARTINDENT
  189.     if (curbuf->b_p_si)        /* need first char after new line break */
  190.     {
  191.         p = skipwhite(p_extra);
  192.         first_char = *p;
  193.     }
  194. #endif
  195.     extra_len = STRLEN(p_extra);
  196.     saved_char = *p_extra;
  197.     *p_extra = NUL;
  198.     }
  199.  
  200.     u_clearline();        /* cannot do "U" command when adding lines */
  201. #ifdef SMARTINDENT
  202.     did_si = FALSE;
  203. #endif
  204.  
  205.     /*
  206.      * If 'autoindent' and/or 'smartindent' is set, try to figure out what
  207.      * indent to use for the new line.
  208.      */
  209.     if (curbuf->b_p_ai
  210. #ifdef SMARTINDENT
  211.             || curbuf->b_p_si
  212. #endif
  213.                         )
  214.     {
  215.     /*
  216.      * count white space on current line
  217.      */
  218.     newindent = get_indent();
  219.     if (newindent == 0)
  220.         newindent = old_indent;    /* for ^^D command in insert mode */
  221.  
  222.     /*
  223.      * If we just did an auto-indent, then we didn't type anything on
  224.      * the prior line, and it should be truncated.
  225.      */
  226.     if (dir == FORWARD && did_ai)
  227.         trunc_line = TRUE;
  228.  
  229. #ifdef SMARTINDENT
  230.     /*
  231.      * Do smart indenting.
  232.      * In insert/replace mode (only when dir == FORWARD)
  233.      * we may move some text to the next line. If it starts with '{'
  234.      * don't add an indent. Fixes inserting a NL before '{' in line
  235.      *    "if (condition) {"
  236.      */
  237.     else if (curbuf->b_p_si && *saved_line != NUL &&
  238.                        (p_extra == NULL || first_char != '{'))
  239.     {
  240.         char_u  *ptr;
  241.         char_u  last_char;
  242.  
  243.         old_cursor = curwin->w_cursor;
  244.         ptr = saved_line;
  245.         lead_len = get_leader_len(ptr, NULL);
  246.         if (dir == FORWARD)
  247.         {
  248.         /*
  249.          * Skip preprocessor directives, unless they are
  250.          * recognised as comments.
  251.          */
  252.         if (lead_len == 0 && ptr[0] == '#')
  253.         {
  254.             while (ptr[0] == '#' && curwin->w_cursor.lnum > 1)
  255.             ptr = ml_get(--curwin->w_cursor.lnum);
  256.             newindent = get_indent();
  257.         }
  258.         lead_len = get_leader_len(ptr, NULL);
  259.         if (lead_len > 0)
  260.         {
  261.             /*
  262.              * This case gets the following right:
  263.              *        \*
  264.              *         * A comment (read '\' as '/').
  265.              *         *\
  266.              * #define IN_THE_WAY
  267.              *        This should line up here;
  268.              */
  269.             p = skipwhite(ptr);
  270.             if (p[0] == '/' && p[1] == '*')
  271.             p++;
  272.             if (p[0] == '*')
  273.             {
  274.             for (p++; *p; p++)
  275.             {
  276.                 if (p[0] == '/' && p[-1] == '*')
  277.                 {
  278.                 /*
  279.                  * End of C comment, indent should line up
  280.                  * with the line containing the start of
  281.                  * the comment
  282.                  */
  283.                 curwin->w_cursor.col = p - ptr;
  284.                 if ((pos = findmatch(NULL, NUL)) != NULL)
  285.                 {
  286.                     curwin->w_cursor.lnum = pos->lnum;
  287.                     newindent = get_indent();
  288.                 }
  289.                 }
  290.             }
  291.             }
  292.         }
  293.         else    /* Not a comment line */
  294.         {
  295.             /* Find last non-blank in line */
  296.             p = ptr + STRLEN(ptr) - 1;
  297.             while (p > ptr && vim_iswhite(*p))
  298.             --p;
  299.             last_char = *p;
  300.  
  301.             /*
  302.              * find the character just before the '{' or ';'
  303.              */
  304.             if (last_char == '{' || last_char == ';')
  305.             {
  306.             if (p > ptr)
  307.                 --p;
  308.             while (p > ptr && vim_iswhite(*p))
  309.                 --p;
  310.             }
  311.             /*
  312.              * Try to catch lines that are split over multiple
  313.              * lines.  eg:
  314.              *        if (condition &&
  315.              *            condition) {
  316.              *        Should line up here!
  317.              *        }
  318.              */
  319.             if (*p == ')')
  320.             {
  321.             curwin->w_cursor.col = p - ptr;
  322.             if ((pos = findmatch(NULL, '(')) != NULL)
  323.             {
  324.                 curwin->w_cursor.lnum = pos->lnum;
  325.                 newindent = get_indent();
  326.                 ptr = ml_get_curline();
  327.             }
  328.             }
  329.             /*
  330.              * If last character is '{' do indent, without
  331.              * checking for "if" and the like.
  332.              */
  333.             if (last_char == '{')
  334.             {
  335.             did_si = TRUE;    /* do indent */
  336.             no_si = TRUE;    /* don't delete it when '{' typed */
  337.             }
  338.             /*
  339.              * Look for "if" and the like, use 'cinwords'.
  340.              * Don't do this if the previous line ended in ';' or
  341.              * '}'.
  342.              */
  343.             else if (last_char != ';' && last_char != '}'
  344.                                && cin_is_cinword(ptr))
  345.             did_si = TRUE;
  346.         }
  347.         }
  348.         else /* dir == BACKWARD */
  349.         {
  350.         /*
  351.          * Skip preprocessor directives, unless they are
  352.          * recognised as comments.
  353.          */
  354.         if (lead_len == 0 && ptr[0] == '#')
  355.         {
  356.             int was_backslashed = FALSE;
  357.  
  358.             while ((ptr[0] == '#' || was_backslashed) &&
  359.              curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
  360.             {
  361.             if (*ptr && ptr[STRLEN(ptr) - 1] == '\\')
  362.                 was_backslashed = TRUE;
  363.             else
  364.                 was_backslashed = FALSE;
  365.             ptr = ml_get(++curwin->w_cursor.lnum);
  366.             }
  367.             if (was_backslashed)
  368.             newindent = 0;        /* Got to end of file */
  369.             else
  370.             newindent = get_indent();
  371.         }
  372.         p = skipwhite(ptr);
  373.         if (*p == '}')        /* if line starts with '}': do indent */
  374.             did_si = TRUE;
  375.         else            /* can delete indent when '{' typed */
  376.             can_si_back = TRUE;
  377.         }
  378.         curwin->w_cursor = old_cursor;
  379.     }
  380.     if (curbuf->b_p_si)
  381.         can_si = TRUE;
  382. #endif /* SMARTINDENT */
  383.  
  384.     did_ai = TRUE;
  385.     }
  386.  
  387.     /*
  388.      * Find out if the current line starts with a comment leader.
  389.      * This may then be inserted in front of the new line.
  390.      */
  391.     lead_len = get_leader_len(saved_line, &lead_flags);
  392.     if (lead_len > 0)
  393.     {
  394.     char_u    *lead_repl = NULL;        /* replaces comment leader */
  395.     int    lead_repl_len = 0;        /* length of *lead_repl */
  396.     char_u    lead_middle[COM_MAX_LEN];   /* middle-comment string */
  397.     char_u    lead_end[COM_MAX_LEN];        /* end-comment string */
  398.     char_u    *comment_end = NULL;        /* where lead_end has been found */
  399.     int    extra_space = FALSE;        /* append extra space */
  400.     int    current_flag;
  401.  
  402.     /*
  403.      * If the comment leader has the start, middle or end flag, it may not
  404.      * be used or may be replaced with the middle leader.
  405.      */
  406.     for (p = lead_flags; *p && *p != ':'; ++p)
  407.     {
  408.         if (*p == COM_START || *p == COM_MIDDLE)
  409.         {
  410.         current_flag = *p;
  411.         if (*p == COM_START)
  412.         {
  413.             /*
  414.              * Doing "O" on a start of comment does not insert leader.
  415.              */
  416.             if (dir == BACKWARD)
  417.             {
  418.             lead_len = 0;
  419.             break;
  420.             }
  421.  
  422.            /* find start of middle part */
  423.             (void)copy_option_part(&p, lead_middle, COM_MAX_LEN, ",");
  424.         }
  425.  
  426.         /*
  427.          * Isolate the strings of the middle and end leader.
  428.          */
  429.         while (*p && p[-1] != ':')    /* find end of middle flags */
  430.             ++p;
  431.         (void)copy_option_part(&p, lead_middle, COM_MAX_LEN, ",");
  432.         while (*p && p[-1] != ':')    /* find end of end flags */
  433.             ++p;
  434.         (void)copy_option_part(&p, lead_end, COM_MAX_LEN, ",");
  435.  
  436.         /*
  437.          * If the end of the comment is in the same line, don't use
  438.          * the comment leader.
  439.          */
  440.         if (dir == FORWARD)
  441.         {
  442.             n = STRLEN(lead_end);
  443.             for (p = saved_line + lead_len; *p; ++p)
  444.             if (STRNCMP(p, lead_end, n) == 0)
  445.             {
  446.                 comment_end = p;
  447.                 lead_len = 0;
  448.                 break;
  449.             }
  450.         }
  451.  
  452.         /*
  453.          * Doing "o" on a start of comment inserts the middle leader.
  454.          */
  455.         if (lead_len)
  456.         {
  457.             if (current_flag == COM_START)
  458.             {
  459.             lead_repl = lead_middle;
  460.             lead_repl_len = STRLEN(lead_middle);
  461.             }
  462.  
  463.             /*
  464.              * If we have hit RETURN immediately after the start
  465.              * comment leader, then put a space after the middle
  466.              * comment leader on the next line.
  467.              */
  468.             if (!vim_iswhite(saved_line[lead_len - 1]) &&
  469.                 ((p_extra != NULL &&
  470.                      (int)curwin->w_cursor.col == lead_len) ||
  471.                  (p_extra == NULL && saved_line[lead_len] == NUL)))
  472.             extra_space = TRUE;
  473.         }
  474.         break;
  475.         }
  476.         if (*p == COM_END)
  477.         {
  478.         /*
  479.          * Doing "o" on the end of a comment does not insert leader.
  480.          * Remember where the end is, might want to use it to find the
  481.          * start (for C-comments).
  482.          */
  483.         if (dir == FORWARD)
  484.         {
  485.             comment_end = skipwhite(saved_line);
  486.             lead_len = 0;
  487.             break;
  488.         }
  489.  
  490.         /*
  491.          * Doing "O" on the end of a comment inserts the middle leader.
  492.          * Find the string for the middle leader, searching backwards.
  493.          */
  494.         while (p > curbuf->b_p_com && *p != ',')
  495.             --p;
  496.         for (lead_repl = p; lead_repl > curbuf->b_p_com &&
  497.                         lead_repl[-1] != ':'; --lead_repl)
  498.             ;
  499.         lead_repl_len = p - lead_repl;
  500.         break;
  501.         }
  502.         if (*p == COM_FIRST)
  503.         {
  504.         /*
  505.          * Comment leader for first line only:    Don't repeat leader
  506.          * when using "O", blank out leader when using "o".
  507.          */
  508.         if (dir == BACKWARD)
  509.             lead_len = 0;
  510.         else
  511.         {
  512.             lead_repl = (char_u *)"";
  513.             lead_repl_len = 0;
  514.         }
  515.         break;
  516.         }
  517.     }
  518.     if (lead_len)
  519.     {
  520.         /* allocate buffer (may concatenate p_exta later) */
  521.         leader = alloc(lead_len + lead_repl_len + extra_space +
  522.                                   extra_len + 1);
  523.         allocated = leader;            /* remember to free it later */
  524.  
  525.         if (leader == NULL)
  526.         lead_len = 0;
  527.         else
  528.         {
  529.         STRNCPY(leader, saved_line, lead_len);
  530.         leader[lead_len] = NUL;
  531.  
  532.         /*
  533.          * Replace leader with lead_repl, right or left adjusted
  534.          */
  535.         if (lead_repl != NULL)
  536.         {
  537.             for (p = lead_flags; *p && *p != ':'; ++p)
  538.             if (*p == COM_RIGHT || *p == COM_LEFT)
  539.                 break;
  540.             if (*p == COM_RIGHT)    /* right adjusted leader */
  541.             {
  542.             /* find last non-white in the leader to line up with */
  543.             for (p = leader + lead_len - 1; p > leader &&
  544.                              vim_iswhite(*p); --p)
  545.                 ;
  546.  
  547.             ++p;
  548.             if (p < leader + lead_repl_len)
  549.                 p = leader;
  550.             else
  551.                 p -= lead_repl_len;
  552.             vim_memmove(p, lead_repl, (size_t)lead_repl_len);
  553.             if (p + lead_repl_len > leader + lead_len)
  554.                 p[lead_repl_len] = NUL;
  555.  
  556.             /* blank-out any other chars from the old leader. */
  557.             while (--p >= leader)
  558.                 if (!vim_iswhite(*p))
  559.                 *p = ' ';
  560.             }
  561.             else            /* left adjusted leader */
  562.             {
  563.             p = skipwhite(leader);
  564.             vim_memmove(p, lead_repl, (size_t)lead_repl_len);
  565.  
  566.             /* blank-out any other chars from the old leader. */
  567.             for (p += lead_repl_len; p < leader + lead_len; ++p)
  568.                 if (!vim_iswhite(*p))
  569.                 *p = ' ';
  570.             *p = NUL;
  571.             }
  572.  
  573.             /* Recompute the indent, it may have changed. */
  574.             if (curbuf->b_p_ai
  575. #ifdef SMARTINDENT
  576.                     || curbuf->b_p_si
  577. #endif
  578.                                )
  579.             newindent = get_indent_str(leader);
  580.         }
  581.  
  582.         lead_len = STRLEN(leader);
  583.         if (extra_space)
  584.         {
  585.             leader[lead_len++] = ' ';
  586.             leader[lead_len] = NUL;
  587.         }
  588.  
  589.         newcol = lead_len;
  590.  
  591.         /*
  592.          * if a new indent will be set below, remove the indent that
  593.          * is in the comment leader
  594.          */
  595.         if (newindent
  596. #ifdef SMARTINDENT
  597.                 || did_si
  598. #endif
  599.                        )
  600.         {
  601.             while (lead_len && vim_iswhite(*leader))
  602.             {
  603.             --lead_len;
  604.             --newcol;
  605.             ++leader;
  606.             }
  607.         }
  608.  
  609.         }
  610. #ifdef SMARTINDENT
  611.         did_si = can_si = FALSE;
  612. #endif
  613.     }
  614.     else if (comment_end != NULL)
  615.     {
  616.         /*
  617.          * We have finished a comment, so we don't use the leader.
  618.          * If this was a C-comment and 'ai' or 'si' is set do a normal
  619.          * indent to align with the line containing the start of the
  620.          * comment.
  621.          */
  622.         if (comment_end[0] == '*' && comment_end[1] == '/' &&
  623.             (curbuf->b_p_ai
  624. #ifdef SMARTINDENT
  625.                     || curbuf->b_p_si
  626. #endif
  627.                                ))
  628.         {
  629.         old_cursor = curwin->w_cursor;
  630.         curwin->w_cursor.col = comment_end - saved_line;
  631.         if ((pos = findmatch(NULL, NUL)) != NULL)
  632.         {
  633.             curwin->w_cursor.lnum = pos->lnum;
  634.             newindent = get_indent();
  635.         }
  636.         curwin->w_cursor = old_cursor;
  637.         }
  638.     }
  639.     }
  640.  
  641.     /* (State == INSERT || State == REPLACE), only when dir == FORWARD */
  642.     if (p_extra != NULL)
  643.     {
  644.     *p_extra = saved_char;        /* restore char that NUL replaced */
  645.  
  646.     /*
  647.      * When 'ai' set or "del_spaces" TRUE, skip to the first non-blank.
  648.      *
  649.      * When in REPLACE mode, put the deleted blanks on the replace stack,
  650.      * preceded by a NUL, so they can be put back when a BS is entered.
  651.      */
  652.     if (State == REPLACE)
  653.         replace_push(NUL);        /* end of extra blanks */
  654.     if (curbuf->b_p_ai || del_spaces)
  655.     {
  656.         while (*p_extra == ' ' || *p_extra == '\t')
  657.         {
  658.         if (State == REPLACE)
  659.             replace_push(*p_extra);
  660.         ++p_extra;
  661.         }
  662.     }
  663.     if (*p_extra != NUL)
  664.         did_ai = FALSE;        /* append some text, don't trucate now */
  665.     }
  666.  
  667.     if (p_extra == NULL)
  668.     p_extra = (char_u *)"";            /* append empty line */
  669.  
  670.     /* concatenate leader and p_extra, if there is a leader */
  671.     if (lead_len)
  672.     {
  673.     STRCAT(leader, p_extra);
  674.     p_extra = leader;
  675.     }
  676.  
  677.     old_cursor = curwin->w_cursor;
  678.     if (dir == BACKWARD)
  679.     --curwin->w_cursor.lnum;
  680.     if (ml_append(curwin->w_cursor.lnum, p_extra, (colnr_t)0, FALSE) == FAIL)
  681.     goto theend;
  682.     changed_line_abv_curs();        /* update cursor screen position later */
  683.     mark_adjust(curwin->w_cursor.lnum + 1, (linenr_t)MAXLNUM, 1L, 0L);
  684.     if (newindent
  685. #ifdef SMARTINDENT
  686.             || did_si
  687. #endif
  688.                 )
  689.     {
  690.     ++curwin->w_cursor.lnum;
  691. #ifdef SMARTINDENT
  692.     if (did_si)
  693.     {
  694.         if (p_sr)
  695.         newindent -= newindent % (int)curbuf->b_p_sw;
  696.         newindent += (int)curbuf->b_p_sw;
  697.     }
  698. #endif
  699.     set_indent(newindent, FALSE);
  700.     /*
  701.      * In REPLACE mode, for each character in the new indent, there must
  702.      * be a NUL on the replace stack, for when it is deleted with BS
  703.      */
  704.     if (State == REPLACE)
  705.         for (n = 0; n < (int)curwin->w_cursor.col; ++n)
  706.         replace_push(NUL);
  707.     newcol += curwin->w_cursor.col;
  708. #ifdef SMARTINDENT
  709.     if (no_si)
  710.         did_si = FALSE;
  711. #endif
  712.     }
  713.     /*
  714.      * In REPLACE mode, for each character in the extra leader, there must be
  715.      * a NUL on the replace stack, for when it is deleted with BS.
  716.      */
  717.     if (State == REPLACE)
  718.     while (lead_len-- > 0)
  719.         replace_push(NUL);
  720.  
  721.     curwin->w_cursor = old_cursor;
  722.  
  723.     if (dir == FORWARD)
  724.     {
  725.     if (redraw)    /* want to know the old number of screen lines */
  726.     {
  727.         old_plines = plines(curwin->w_cursor.lnum);
  728.         new_plines = old_plines;
  729.     }
  730.     if (trunc_line || State == INSERT || State == REPLACE)
  731.     {
  732.         if (trunc_line)
  733.         {
  734.         /* find start of trailing white space */
  735.         for (n = STRLEN(saved_line); n > 0 &&
  736.                       vim_iswhite(saved_line[n - 1]); --n)
  737.             ;
  738.         saved_line[n] = NUL;
  739.         }
  740.         else            /* truncate current line at cursor */
  741.         *(saved_line + curwin->w_cursor.col) = NUL;
  742.         ml_replace(curwin->w_cursor.lnum, saved_line, FALSE);
  743.         saved_line = NULL;
  744.         if (redraw)
  745.         new_plines = plines(curwin->w_cursor.lnum);
  746.     }
  747.  
  748.     /*
  749.      * Get the cursor to the start of the line, so that 'curwin->w_wrow'
  750.      * gets set to the right physical line number for the stuff that
  751.      * follows...
  752.      */
  753.     curwin->w_cursor.col = 0;
  754.  
  755.     if (redraw)
  756.     {
  757.         /*
  758.          * If we're doing an open on the last logical line, then go ahead
  759.          * and scroll the screen up. Otherwise, just insert blank lines
  760.          * at the right place if the number of screen lines changed.
  761.          * We use calls to plines() in case the cursor is resting on a
  762.          * long line, we want to know the row below the line.
  763.          *
  764.          * Note: using w_cline_row from before the change!
  765.          */
  766.         n = curwin->w_cline_row + new_plines;
  767.         if (n + plines(curwin->w_cursor.lnum + 1) - 1 >=
  768.                               curwin->w_height - p_so)
  769.         scrollup(1L);
  770.         else
  771.         win_ins_lines(curwin, n,
  772.           plines(curwin->w_cursor.lnum + 1) + new_plines - old_plines,
  773.                                   TRUE, TRUE);
  774.     }
  775.  
  776.     /*
  777.      * Put the cursor on the new line.  Careful: the scrollup() above may
  778.      * have moved w_cursor, we must use old_cursor.
  779.      */
  780.     curwin->w_cursor.lnum = old_cursor.lnum + 1;
  781.     }
  782.     else if (redraw)
  783.     {
  784.     /*
  785.      * Insert physical line above current line.
  786.      * Note: use w_cline_row from before the change.
  787.      */
  788.     win_ins_lines(curwin, curwin->w_cline_row, 1, TRUE, TRUE);
  789.     }
  790.  
  791.     curwin->w_cursor.col = newcol;
  792.  
  793. #ifdef LISPINDENT
  794.     /*
  795.      * May do lisp indenting.
  796.      */
  797.     if (leader == NULL && curbuf->b_p_lisp && curbuf->b_p_ai)
  798.     fixthisline(get_lisp_indent);
  799. #endif
  800. #ifdef CINDENT
  801.     /*
  802.      * May do indenting after opening a new line.
  803.      */
  804.     if (leader == NULL && curbuf->b_p_cin &&
  805.         in_cinkeys(dir == FORWARD ? KEY_OPEN_FORW :
  806.             KEY_OPEN_BACK, ' ', linewhite(curwin->w_cursor.lnum)))
  807.     fixthisline(get_c_indent);
  808. #endif
  809.  
  810.     /*
  811.      * w_botline won't change much when inserting a new line.
  812.      */
  813.     approximate_botline();
  814.  
  815.     if (redraw > 0)
  816.     {
  817.     update_topline();
  818.     update_screen(VALID_BEF_CURSCHAR);
  819.     }
  820.     CHANGED;
  821.  
  822.     retval = TRUE;        /* success! */
  823. theend:
  824.     vim_free(saved_line);
  825.     vim_free(allocated);
  826.     return retval;
  827. }
  828.  
  829. /*
  830.  * get_leader_len() returns the length of the prefix of the given string
  831.  * which introduces a comment.    If this string is not a comment then 0 is
  832.  * returned.
  833.  * When "flags" is non-zero, it is set to point to the flags of the recognized
  834.  * comment leader.
  835.  */
  836.     int
  837. get_leader_len(line, flags)
  838.     char_u  *line;
  839.     char_u  **flags;
  840. {
  841.     int        i, j;
  842.     int        got_com = FALSE;
  843.     int        found_one;
  844.     char_u  part_buf[COM_MAX_LEN];  /* buffer for one option part */
  845.     char_u  *string;            /* pointer to comment string */
  846.     char_u  *list;
  847.  
  848.     if (!fo_do_comments)        /* don't format comments at all */
  849.     return 0;
  850.  
  851.     i = 0;
  852.     while (vim_iswhite(line[i]))    /* leading white space is ignored */
  853.     ++i;
  854.  
  855.     /*
  856.      * Repeat to match several nested comment strings.
  857.      */
  858.     while (line[i])
  859.     {
  860.     /*
  861.      * scan through the 'comments' option for a match
  862.      */
  863.     found_one = FALSE;
  864.     for (list = curbuf->b_p_com; *list; )
  865.     {
  866.         /*
  867.          * Get one option part into part_buf[].  Advance list to next one.
  868.          * put string at start of string.
  869.          */
  870.         if (!got_com && flags != NULL)  /* remember where flags started */
  871.         *flags = list;
  872.         (void)copy_option_part(&list, part_buf, COM_MAX_LEN, ",");
  873.         string = vim_strchr(part_buf, ':');
  874.         if (string == NULL)        /* missing ':', ignore this part */
  875.         continue;
  876.         *string++ = NUL;        /* isolate flags from string */
  877.  
  878.         /*
  879.          * When already found a nested comment, only accept further
  880.          * nested comments.
  881.          */
  882.         if (got_com && vim_strchr(part_buf, COM_NEST) == NULL)
  883.         continue;
  884.  
  885.         /*
  886.          * Line contents and string must match.
  887.          */
  888.         for (j = 0; string[j] != NUL && string[j] == line[i + j]; ++j)
  889.         ;
  890.         if (string[j] != NUL)
  891.         continue;
  892.  
  893.         /*
  894.          * When 'b' flag used, there must be white space or an
  895.          * end-of-line after the string in the line.
  896.          */
  897.         if (vim_strchr(part_buf, COM_BLANK) != NULL &&
  898.                   !vim_iswhite(line[i + j]) && line[i + j] != NUL)
  899.         continue;
  900.  
  901.         /*
  902.          * We have found a match, stop searching.
  903.          */
  904.         i += j;
  905.         got_com = TRUE;
  906.         found_one = TRUE;
  907.         break;
  908.     }
  909.  
  910.     /*
  911.      * No match found, stop scanning.
  912.      */
  913.     if (!found_one)
  914.         break;
  915.  
  916.     /*
  917.      * Include any trailing white space.
  918.      */
  919.     while (vim_iswhite(line[i]))
  920.         ++i;
  921.  
  922.     /*
  923.      * If this comment doesn't nest, stop here.
  924.      */
  925.     if (vim_strchr(part_buf, COM_NEST) == NULL)
  926.         break;
  927.     }
  928.     return (got_com ? i : 0);
  929. }
  930.  
  931. /*
  932.  * plines(p) - return the number of physical screen lines taken by line 'p'
  933.  */
  934.     int
  935. plines(p)
  936.     linenr_t    p;
  937. {
  938.     return plines_win(curwin, p);
  939. }
  940.  
  941.     int
  942. plines_win(wp, p)
  943.     WIN        *wp;
  944.     linenr_t    p;
  945. {
  946.     long    col;
  947.     char_u    *s;
  948.     int        lines;
  949.  
  950.     if (!wp->w_p_wrap)
  951.     return 1;
  952.  
  953.     s = ml_get_buf(wp->w_buffer, p, FALSE);
  954.     if (*s == NUL)        /* empty line */
  955.     return 1;
  956.  
  957.     col = win_linetabsize(wp, s);
  958.  
  959.     /*
  960.      * If list mode is on, then the '$' at the end of the line takes up one
  961.      * extra column.
  962.      */
  963.     if (wp->w_p_list)
  964.     col += 1;
  965.  
  966.     /*
  967.      * If 'number' mode is on, add another 8.
  968.      */
  969.     if (wp->w_p_nu)
  970.     col += 8;
  971.  
  972.     lines = (col + (Columns - 1)) / Columns;
  973.     if (lines <= wp->w_height)
  974.     return lines;
  975.     return (int)(wp->w_height);        /* maximum length */
  976. }
  977.  
  978. /*
  979.  * Like plines_win(), but only reports the number of physical screen lines used
  980.  * from the start of the line to the given column number.
  981.  */
  982.     int
  983. plines_win_col(wp, p, column)
  984.     WIN        *wp;
  985.     linenr_t    p;
  986.     long    column;
  987. {
  988.     register long    col;
  989.     register char_u    *s;
  990.     register int    lines;
  991.  
  992.     if (!wp->w_p_wrap)
  993.     return 1;
  994.  
  995.     s = ml_get_buf(wp->w_buffer, p, FALSE);
  996.  
  997.     col = 0;
  998.     while (*s != NUL && --column >= 0)
  999.     col += win_lbr_chartabsize(wp, s++, (colnr_t)col, NULL);
  1000.  
  1001.     /*
  1002.      * If *s is a TAB, and the TAB is not displayed as ^I, and we're not in
  1003.      * INSERT mode, then col must be adjusted so that it represents the last
  1004.      * screen position of the TAB.  This only fixes an error when the TAB wraps
  1005.      * from one screen line to the next (when 'columns' is not a multiple of
  1006.      * 'ts') -- webb.
  1007.      */
  1008.     if (*s == TAB && (State & NORMAL) && !wp->w_p_list)
  1009.     col += win_lbr_chartabsize(wp, s, (colnr_t)col, NULL) - 1;
  1010.  
  1011.     /*
  1012.      * If 'number' mode is on, add another 8.
  1013.      */
  1014.     if (wp->w_p_nu)
  1015.     col += 8;
  1016.  
  1017.     lines = 1 + col / Columns;
  1018.     if (lines <= wp->w_height)
  1019.     return lines;
  1020.     return (int)(wp->w_height);        /* maximum length */
  1021. }
  1022.  
  1023.  
  1024. /*
  1025.  * Count the physical lines (rows) for the lines "first" to "last" inclusive.
  1026.  */
  1027.     int
  1028. plines_m(first, last)
  1029.     linenr_t        first, last;
  1030. {
  1031.     return plines_m_win(curwin, first, last);
  1032. }
  1033.  
  1034.     int
  1035. plines_m_win(wp, first, last)
  1036.     WIN            *wp;
  1037.     linenr_t        first, last;
  1038. {
  1039.     int count = 0;
  1040.  
  1041.     while (first <= last)
  1042.     count += plines_win(wp, first++);
  1043.     return (count);
  1044. }
  1045.  
  1046. /*
  1047.  * Insert or replace a single character at the cursor position.
  1048.  * When in REPLACE mode, replace any existing character.
  1049.  */
  1050.     void
  1051. ins_char(c)
  1052.     int        c;
  1053. {
  1054.     char_u        *p;
  1055.     char_u        *newp;
  1056.     char_u        *oldp;
  1057.     int            oldlen;
  1058.     int            extra;
  1059.     colnr_t        col = curwin->w_cursor.col;
  1060.     linenr_t        lnum = curwin->w_cursor.lnum;
  1061.  
  1062.     oldp = ml_get(lnum);
  1063.     oldlen = STRLEN(oldp) + 1;
  1064.  
  1065.     if (State != REPLACE || *(oldp + col) == NUL)
  1066.     extra = 1;
  1067.     else
  1068.     extra = 0;
  1069.  
  1070.     /*
  1071.      * A character has to be put on the replace stack if there is a
  1072.      * character that is replaced, so it can be put back when BS is used.
  1073.      */
  1074.     if (State == REPLACE)
  1075.     {
  1076.     replace_push(NUL);
  1077.     if (!extra)
  1078.         replace_push(*(oldp + col));
  1079.     }
  1080.     newp = alloc_check((unsigned)(oldlen + extra));
  1081.     if (newp == NULL)
  1082.     return;
  1083.     vim_memmove(newp, oldp, (size_t)col);
  1084.     p = newp + col;
  1085.     vim_memmove(p + extra, oldp + col, (size_t)(oldlen - col));
  1086.     *p = c;
  1087.     ml_replace(lnum, newp, FALSE);
  1088.  
  1089.     /*
  1090.      * If we're in insert or replace mode and 'showmatch' is set, then check for
  1091.      * right parens and braces. If there isn't a match, then beep. If there
  1092.      * is a match AND it's on the screen, then flash to it briefly. If it
  1093.      * isn't on the screen, don't do anything.
  1094.      */
  1095. #ifdef RIGHTLEFT
  1096.     if (p_sm && (State & INSERT) &&
  1097.     ((!(curwin->w_p_rl ^ p_ri) && (c == ')' || c == '}' || c == ']')) ||
  1098.      ((curwin->w_p_rl ^ p_ri) && (c == '(' || c == '{' || c == '['))))
  1099. #else
  1100.     if (p_sm && (State & INSERT) && (c == ')' || c == '}' || c == ']'))
  1101. #endif
  1102.     showmatch();
  1103.  
  1104. #ifdef RIGHTLEFT
  1105.     if (!p_ri || State == REPLACE)    /* normal insert: cursor right */
  1106. #endif
  1107.     ++curwin->w_cursor.col;
  1108.     CHANGED;
  1109.     /*
  1110.      * TODO: should try to update w_row here, to avoid recomputing it later.
  1111.      */
  1112.     changed_cline_bef_curs();
  1113.     approximate_botline();    /* w_botline might have changed */
  1114. }
  1115.  
  1116. /*
  1117.  * Insert a string at the cursor position.
  1118.  * Note: Nothing special for replace mode.
  1119.  */
  1120.     void
  1121. ins_str(s)
  1122.     char_u  *s;
  1123. {
  1124.     char_u    *oldp, *newp;
  1125.     int        newlen = STRLEN(s);
  1126.     int        oldlen;
  1127.     colnr_t    col = curwin->w_cursor.col;
  1128.     linenr_t    lnum = curwin->w_cursor.lnum;
  1129.  
  1130.     oldp = ml_get(lnum);
  1131.     oldlen = STRLEN(oldp);
  1132.  
  1133.     newp = alloc_check((unsigned)(oldlen + newlen + 1));
  1134.     if (newp == NULL)
  1135.     return;
  1136.     vim_memmove(newp, oldp, (size_t)col);
  1137.     vim_memmove(newp + col, s, (size_t)newlen);
  1138.     vim_memmove(newp + col + newlen, oldp + col, (size_t)(oldlen - col + 1));
  1139.     ml_replace(lnum, newp, FALSE);
  1140.     curwin->w_cursor.col += newlen;
  1141.     CHANGED;
  1142.     changed_cline_bef_curs();
  1143.     approximate_botline();    /* w_botline might have changed */
  1144. }
  1145.  
  1146. /*
  1147.  * Delete one character under the cursor.
  1148.  * If 'fixpos' is TRUE, don't let the cursor on the NUL after the line.
  1149.  *
  1150.  * return FAIL for failure, OK otherwise
  1151.  */
  1152.     int
  1153. del_char(fixpos)
  1154.     int        fixpos;
  1155. {
  1156.     return del_chars(1L, fixpos);
  1157. }
  1158.  
  1159. /*
  1160.  * Delete 'count' characters under the cursor.
  1161.  * If 'fixpos' is TRUE, don't leave the cursor on the NUL after the line.
  1162.  *
  1163.  * return FAIL for failure, OK otherwise
  1164.  */
  1165.     int
  1166. del_chars(count, fixpos)
  1167.     long    count;
  1168.     int        fixpos;
  1169. {
  1170.     char_u    *oldp, *newp;
  1171.     colnr_t    oldlen;
  1172.     linenr_t    lnum = curwin->w_cursor.lnum;
  1173.     colnr_t    col = curwin->w_cursor.col;
  1174.     int        was_alloced;
  1175.     long    movelen;
  1176.  
  1177.     oldp = ml_get(lnum);
  1178.     oldlen = STRLEN(oldp);
  1179.  
  1180.     /*
  1181.      * Can't do anything when the cursor is on the NUL after the line.
  1182.      */
  1183.     if (col >= oldlen)
  1184.     return FAIL;
  1185.  
  1186.     /*
  1187.      * When count is too big, reduce it.
  1188.      */
  1189.     movelen = (long)oldlen - (long)col - count + 1; /* includes trailing NUL */
  1190.     if (movelen <= 1)
  1191.     {
  1192.     /*
  1193.      * If we just took off the last character of a non-blank line, and
  1194.      * fixpos is TRUE, we don't want to end up positioned at the NUL.
  1195.      */
  1196.     if (col > 0 && fixpos)
  1197.         --curwin->w_cursor.col;
  1198.     count = oldlen - col;
  1199.     movelen = 1;
  1200.     }
  1201.  
  1202.     /*
  1203.      * If the old line has been allocated the deletion can be done in the
  1204.      * existing line. Otherwise a new line has to be allocated
  1205.      */
  1206.     was_alloced = ml_line_alloced();        /* check if oldp was allocated */
  1207.     if (was_alloced)
  1208.     newp = oldp;                /* use same allocated memory */
  1209.     else
  1210.     {                        /* need to allocated a new line */
  1211.     newp = alloc((unsigned)(oldlen + 1 - count));
  1212.     if (newp == NULL)
  1213.         return FAIL;
  1214.     vim_memmove(newp, oldp, (size_t)col);
  1215.     }
  1216.     vim_memmove(newp + col, oldp + col + count, (size_t)movelen);
  1217.     if (!was_alloced)
  1218.     ml_replace(lnum, newp, FALSE);
  1219.  
  1220.     CHANGED;
  1221.  
  1222.     /*
  1223.      * When the new character under the cursor is a TAB, the cursor will move
  1224.      * on the screen, so we can't use changed_cline_aft_curs() here.
  1225.      */
  1226.     changed_cline_bef_curs();
  1227.     approximate_botline();    /* w_botline might have changed */
  1228.     return OK;
  1229. }
  1230.  
  1231. /*
  1232.  * Delete from cursor to end of line.
  1233.  *
  1234.  * return FAIL for failure, OK otherwise
  1235.  */
  1236.     int
  1237. truncate_line(fixpos)
  1238.     int        fixpos;        /* if TRUE fix the cursor position when done */
  1239. {
  1240.     char_u    *newp;
  1241.     linenr_t    lnum = curwin->w_cursor.lnum;
  1242.     colnr_t    col = curwin->w_cursor.col;
  1243.  
  1244.     if (col == 0)
  1245.     newp = vim_strsave((char_u *)"");
  1246.     else
  1247.     newp = vim_strnsave(ml_get(lnum), col);
  1248.  
  1249.     if (newp == NULL)
  1250.     return FAIL;
  1251.  
  1252.     ml_replace(lnum, newp, FALSE);
  1253.  
  1254.     /*
  1255.      * If "fixpos" is TRUE we don't want to end up positioned at the NUL.
  1256.      */
  1257.     if (fixpos && curwin->w_cursor.col > 0)
  1258.     --curwin->w_cursor.col;
  1259.  
  1260.     CHANGED;
  1261.     changed_cline_bef_curs();
  1262.     approximate_botline();    /* w_botline might have changed */
  1263.     return OK;
  1264. }
  1265.  
  1266.     void
  1267. del_lines(nlines, dowindow, undo)
  1268.     long        nlines;        /* number of lines to delete */
  1269.     int            dowindow;        /* if true, update the window */
  1270.     int            undo;        /* if true, prepare for undo */
  1271. {
  1272.     int            num_plines = 0;
  1273.  
  1274.     if (nlines <= 0)
  1275.     return;
  1276.     /*
  1277.      * There's no point in keeping the window updated if redrawing is disabled
  1278.      * or we're deleting more than a window's worth of lines.
  1279.      */
  1280.     if (!redrawing() || !botline_approximated())
  1281.     dowindow = FALSE;
  1282.     else
  1283.     {
  1284.     validate_cursor();
  1285.     if (nlines > (curwin->w_height - curwin->w_wrow) && dowindow)
  1286.     {
  1287.         dowindow = FALSE;
  1288.         /* flaky way to clear rest of window */
  1289.         win_del_lines(curwin, curwin->w_wrow, curwin->w_height, TRUE, TRUE);
  1290.     }
  1291.     }
  1292.  
  1293.     /*
  1294.      * Assume that w_botline won't change much.  If it does, there is a small
  1295.      * risc of an extra redraw or scroll-up.
  1296.      */
  1297.     approximate_botline();
  1298.  
  1299.     /* save the deleted lines for undo */
  1300.     if (undo && u_savedel(curwin->w_cursor.lnum, nlines) == FAIL)
  1301.     return;
  1302.  
  1303.     /* adjust marks for deleted lines and lines that follow */
  1304.     mark_adjust(curwin->w_cursor.lnum, curwin->w_cursor.lnum + nlines - 1,
  1305.                           (linenr_t)MAXLNUM, -nlines);
  1306.  
  1307.     while (nlines-- > 0)
  1308.     {
  1309.     if (curbuf->b_ml.ml_flags & ML_EMPTY)        /* nothing to delete */
  1310.         break;
  1311.  
  1312.     /*
  1313.      * Set up to delete the correct number of physical lines on the
  1314.      * window
  1315.      */
  1316.     if (dowindow)
  1317.         num_plines += plines(curwin->w_cursor.lnum);
  1318.  
  1319.     ml_delete(curwin->w_cursor.lnum, TRUE);
  1320.  
  1321.     CHANGED;
  1322.  
  1323.     /* If we delete the last line in the file, stop */
  1324.     if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
  1325.     {
  1326.         curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  1327.         break;
  1328.     }
  1329.     }
  1330.     curwin->w_cursor.col = 0;
  1331.     /*
  1332.      * The cursor will stay in the same line number, but the contents will be
  1333.      * different, so need to update it's screen posision later.
  1334.      */
  1335.     changed_cline_bef_curs();
  1336.  
  1337.     /*
  1338.      * Delete the correct number of physical lines on the window
  1339.      */
  1340.     if (dowindow && num_plines > 0)
  1341.     {
  1342.     validate_cline_row();
  1343.     win_del_lines(curwin, curwin->w_cline_row, num_plines, TRUE, TRUE);
  1344.     }
  1345. }
  1346.  
  1347.     int
  1348. gchar(pos)
  1349.     FPOS *pos;
  1350. {
  1351.     return (int)(*(ml_get_pos(pos)));
  1352. }
  1353.  
  1354.     int
  1355. gchar_cursor()
  1356. {
  1357.     return (int)(*(ml_get_cursor()));
  1358. }
  1359.  
  1360. /*
  1361.  * Write a character at the current cursor position.
  1362.  * It is directly written into the block.
  1363.  */
  1364.     void
  1365. pchar_cursor(c)
  1366.     int c;
  1367. {
  1368.     *(ml_get_buf(curbuf, curwin->w_cursor.lnum, TRUE) +
  1369.                             curwin->w_cursor.col) = c;
  1370. }
  1371.  
  1372. /*
  1373.  * Put *pos at end of current buffer
  1374.  */
  1375.     void
  1376. goto_endofbuf(pos)
  1377.     FPOS    *pos;
  1378. {
  1379.     char_u  *p;
  1380.  
  1381.     pos->lnum = curbuf->b_ml.ml_line_count;
  1382.     pos->col = 0;
  1383.     p = ml_get(pos->lnum);
  1384.     while (*p++)
  1385.     ++pos->col;
  1386. }
  1387.  
  1388. /*
  1389.  * When extra == 0: Return TRUE if the cursor is before or on the first
  1390.  *            non-blank in the line.
  1391.  * When extra == 1: Return TRUE if the cursor is before the first non-blank in
  1392.  *            the line.
  1393.  */
  1394.     int
  1395. inindent(extra)
  1396.     int        extra;
  1397. {
  1398.     char_u    *ptr;
  1399.     colnr_t    col;
  1400.  
  1401.     for (col = 0, ptr = ml_get_curline(); vim_iswhite(*ptr); ++col)
  1402.     ++ptr;
  1403.     if (col >= curwin->w_cursor.col + extra)
  1404.     return TRUE;
  1405.     else
  1406.     return FALSE;
  1407. }
  1408.  
  1409. /*
  1410.  * Skip to next part of an option argument: Skip space and comma.
  1411.  */
  1412.     char_u *
  1413. skip_to_option_part(p)
  1414.     char_u  *p;
  1415. {
  1416.     if (*p == ',')
  1417.     ++p;
  1418.     while (*p == ' ')
  1419.     ++p;
  1420.     return p;
  1421. }
  1422.  
  1423.     char *
  1424. plural(n)
  1425.     long n;
  1426. {
  1427.     static char buf[2] = "s";
  1428.  
  1429.     if (n == 1)
  1430.     return &(buf[1]);
  1431.     return &(buf[0]);
  1432. }
  1433.  
  1434. /*
  1435.  * set_Changed is called when something in the current buffer is changed
  1436.  */
  1437.     void
  1438. set_Changed()
  1439. {
  1440.     int        save_msg_scroll = msg_scroll;
  1441.  
  1442.     if (!curbuf->b_changed)
  1443.     {
  1444.     change_warning(0);
  1445.     if (curbuf->b_may_swap)        /* still need to create a swap file */
  1446.     {
  1447.         ml_open_file(curbuf);
  1448.  
  1449.         /* The ml_open_file() can cause an ATTENTION message.
  1450.          * Wait two seconds, to make sure the user reads this unexpected
  1451.          * message.  Since we could be anywhere, call wait_return() now,
  1452.          * and don't let the emsg() set msg_scroll. */
  1453.         if (need_wait_return)
  1454.         {
  1455.         out_flush();
  1456.         ui_delay(2000L, TRUE);
  1457.         wait_return(TRUE);
  1458.         msg_scroll = save_msg_scroll;
  1459.         }
  1460.     }
  1461.     curbuf->b_changed = TRUE;
  1462.     check_status(curbuf);
  1463.     }
  1464.     modified = TRUE;            /* used for redrawing */
  1465.     tag_modified = TRUE;        /* used for tag searching check */
  1466. }
  1467.  
  1468. /*
  1469.  * unset_Changed is called when the changed flag must be reset for buffer 'buf'
  1470.  */
  1471.     void
  1472. unset_Changed(buf)
  1473.     BUF        *buf;
  1474. {
  1475.     if (buf->b_changed)
  1476.     {
  1477.     buf->b_changed = 0;
  1478.     check_status(buf);
  1479.     }
  1480. }
  1481.  
  1482. /*
  1483.  * check_status: called when the status bars for the buffer 'buf'
  1484.  *         need to be updated
  1485.  */
  1486.     void
  1487. check_status(buf)
  1488.     BUF        *buf;
  1489. {
  1490.     WIN        *wp;
  1491.     int        i;
  1492.  
  1493.     i = 0;
  1494.     for (wp = firstwin; wp != NULL; wp = wp->w_next)
  1495.     if (wp->w_buffer == buf && wp->w_status_height)
  1496.     {
  1497.         wp->w_redr_status = TRUE;
  1498.         ++i;
  1499.     }
  1500.     if (i)
  1501.     redraw_later(NOT_VALID);
  1502. }
  1503.  
  1504. /*
  1505.  * If the file is readonly, give a warning message with the first change.
  1506.  * Don't do this for autocommands.
  1507.  * Don't use emsg(), because it flushes the macro buffer.
  1508.  * If we have undone all changes b_changed will be FALSE, but b_did_warn
  1509.  * will be TRUE.
  1510.  */
  1511.     void
  1512. change_warning(col)
  1513.     int        col;        /* column for message; non-zero when in insert
  1514.                    mode and 'showmode' is on */
  1515. {
  1516.     if (curbuf->b_did_warn == FALSE
  1517.         && curbuf_changed() == 0
  1518.         && !p_im
  1519. #ifdef AUTOCMD
  1520.         && !autocmd_busy
  1521. #endif
  1522.         && curbuf->b_p_ro)
  1523.     {
  1524.     /*
  1525.      * Do what msg() does, but with a column offset.
  1526.      */
  1527.     msg_start();
  1528.     msg_col = col;
  1529.     MSG_PUTS_ATTR("Warning: Changing a readonly file",
  1530.                                highlight_attr[HLF_W]);
  1531.     msg_clr_eos();
  1532.     (void)msg_end();
  1533.     ui_delay(1000L, TRUE);    /* give him some time to think about it */
  1534.     curbuf->b_did_warn = TRUE;
  1535.     redraw_cmdline = FALSE;    /* don't redraw and erase the message */
  1536.     }
  1537. }
  1538.  
  1539. /*
  1540.  * Ask for a reply from the user, a 'y' or a 'n'.
  1541.  * No other characters are accepted, the message is repeated until a valid
  1542.  * reply is entered or CTRL-C is hit.
  1543.  * If direct is TRUE, don't use vgetc() but ui_inchar(), don't get characters
  1544.  * from any buffers but directly from the user.
  1545.  *
  1546.  * return the 'y' or 'n'
  1547.  */
  1548.     int
  1549. ask_yesno(str, direct)
  1550.     char_u  *str;
  1551.     int        direct;
  1552. {
  1553.     int        r = ' ';
  1554.     char_u  buf[20];
  1555.     int        len = 0;
  1556.     int        idx = 0;
  1557.  
  1558.     if (exiting)        /* put terminal in raw mode for this question */
  1559.     settmode(TMODE_RAW);
  1560.     ++no_wait_return;
  1561. #ifdef USE_GUI_WIN32
  1562.     dont_scroll = TRUE;        /* disallow scrolling here */
  1563. #endif
  1564.     while (r != 'y' && r != 'n')
  1565.     {
  1566.     /* same highlighting as for wait_return */
  1567.     smsg_attr(highlight_attr[HLF_R], (char_u *)"%s (y/n)?", str);
  1568.     if (direct)
  1569.     {
  1570.         out_flush();
  1571.         if (idx >= len)
  1572.         {
  1573.         len = ui_inchar(buf, 20, -1L);
  1574.         idx = 0;
  1575.         }
  1576.         r = buf[idx++];
  1577.     }
  1578.     else
  1579.         r = vgetc();
  1580.     if (r == Ctrl('C') || r == ESC)
  1581.         r = 'n';
  1582.     msg_putchar(r);        /* show what you typed */
  1583.     out_flush();
  1584.     }
  1585.     --no_wait_return;
  1586.     return r;
  1587. }
  1588.  
  1589. /*
  1590.  * get a number from the user
  1591.  */
  1592.     int
  1593. get_number(colon)
  1594.     int    colon;            /* allow colon to abort */
  1595. {
  1596.     int    n = 0;
  1597.     int    c;
  1598.  
  1599. #ifdef USE_GUI_WIN32
  1600.     dont_scroll = TRUE;        /* disallow scrolling here */
  1601. #endif
  1602.     for (;;)
  1603.     {
  1604.     windgoto(msg_row, msg_col);
  1605.     c = vgetc();
  1606.     if (vim_isdigit(c))
  1607.     {
  1608.         n = n * 10 + c - '0';
  1609.         msg_putchar(c);
  1610.     }
  1611.     else if (c == K_DEL || c == K_BS || c == Ctrl('H'))
  1612.     {
  1613.         n /= 10;
  1614.         MSG_PUTS("\b \b");
  1615.     }
  1616.     else if (n == 0 && c == ':' && colon)
  1617.     {
  1618.         stuffcharReadbuff(':');
  1619.         if (!exmode_active)
  1620.         cmdline_row = msg_row;
  1621.         skip_redraw = TRUE;        /* skip redraw once */
  1622.         do_redraw = FALSE;
  1623.         break;
  1624.     }
  1625.     else if (c == CR || c == NL || c == Ctrl('C') || c == ESC)
  1626.         break;
  1627.     }
  1628.     return n;
  1629. }
  1630.  
  1631.     void
  1632. msgmore(n)
  1633.     long n;
  1634. {
  1635.     long pn;
  1636.  
  1637.     if (global_busy ||        /* no messages now, wait until global is finished */
  1638.         keep_msg ||        /* there is a message already, skip this one */
  1639.         !messaging())   /* 'lazyredraw' set, don't do messages now */
  1640.     return;
  1641.  
  1642.     if (n > 0)
  1643.     pn = n;
  1644.     else
  1645.     pn = -n;
  1646.  
  1647.     if (pn > p_report)
  1648.     {
  1649.     sprintf((char *)msg_buf, "%ld %s line%s %s",
  1650.         pn, n > 0 ? "more" : "fewer", plural(pn),
  1651.         got_int ? "(Interrupted)" : "");
  1652.     if (msg(msg_buf))
  1653.     {
  1654.         keep_msg = msg_buf;
  1655.         keep_msg_attr = 0;
  1656.     }
  1657.     }
  1658. }
  1659.  
  1660. /*
  1661.  * flush map and typeahead buffers and give a warning for an error
  1662.  */
  1663.     void
  1664. beep_flush()
  1665. {
  1666.     flush_buffers(FALSE);
  1667.     vim_beep();
  1668. }
  1669.  
  1670. /*
  1671.  * give a warning for an error
  1672.  */
  1673.     void
  1674. vim_beep()
  1675. {
  1676.     if (p_vb)
  1677.     {
  1678.     out_str(T_VB);
  1679.     }
  1680.     else
  1681.     {
  1682. #ifdef MSDOS
  1683.     /*
  1684.      * The number of beeps outputted is reduced to avoid having to wait
  1685.      * for all the beeps to finish. This is only a problem on systems
  1686.      * where the beeps don't overlap.
  1687.      */
  1688.     if (beep_count == 0 || beep_count == 10)
  1689.     {
  1690.         out_char('\007');
  1691.         beep_count = 1;
  1692.     }
  1693.     else
  1694.         ++beep_count;
  1695. #else
  1696.     out_char('\007');
  1697. #endif
  1698.     }
  1699. }
  1700.  
  1701. /*
  1702.  * To get the "real" home directory:
  1703.  * - get value of $HOME
  1704.  * For Unix:
  1705.  *  - go to that directory
  1706.  *  - do mch_dirname() to get the real name of that directory.
  1707.  *  This also works with mounts and links.
  1708.  *  Don't do this for MS-DOS, it will change the "current dir" for a drive.
  1709.  */
  1710. static char_u    *homedir = NULL;
  1711.  
  1712.     void
  1713. init_homedir()
  1714. {
  1715.     char_u  *var;
  1716.  
  1717.     var = vim_getenv((char_u *)"HOME");
  1718. #if defined(OS2) || defined(MSDOS) || defined(WIN32)
  1719.     /*
  1720.      * Default home dir is C:/
  1721.      * Best assumption we can make in such a situation.
  1722.      */
  1723.     if (var == NULL)
  1724.     var = "C:/";
  1725. #endif
  1726.     if (var != NULL)
  1727.     {
  1728. #ifdef UNIX
  1729.     if (mch_dirname(NameBuff, MAXPATHL) == OK)
  1730.     {
  1731.         if (!vim_chdir((char *)var) && mch_dirname(IObuff, IOSIZE) == OK)
  1732.         var = IObuff;
  1733.         vim_chdir((char *)NameBuff);
  1734.     }
  1735. #endif
  1736.     homedir = vim_strsave(var);
  1737.     }
  1738. }
  1739.  
  1740. /*
  1741.  * Expand environment variable with path name.
  1742.  * "~/" is also expanded, using $HOME.    For Unix "~user/" is expanded.
  1743.  * If anything fails no expansion is done and dst equals src.
  1744.  */
  1745.     void
  1746. expand_env(src, dst, dstlen)
  1747.     char_u  *src;        /* input string e.g. "$HOME/vim.hlp" */
  1748.     char_u  *dst;        /* where to put the result */
  1749.     int        dstlen;        /* maximum length of the result */
  1750. {
  1751.     char_u  *tail;
  1752.     int        c;
  1753.     char_u  *var;
  1754.     int        copy_char;
  1755.     int        mustfree;        /* var was allocated, need to free it later */
  1756.     char_u  *p;
  1757.     int        at_start = TRUE;
  1758.  
  1759.     src = skipwhite(src);
  1760.     --dstlen;            /* leave one char space for "\," */
  1761.     while (*src && dstlen > 0)
  1762.     {
  1763.     copy_char = TRUE;
  1764.     if (*src == '$' || (*src == '~' && at_start))
  1765.     {
  1766.         mustfree = FALSE;
  1767.  
  1768.         /*
  1769.          * The variable name is copied into dst temporarily, because it may
  1770.          * be a string in read-only memory and a NUL needs to be inserted.
  1771.          */
  1772.         if (*src == '$')                /* environment var */
  1773.         {
  1774.         tail = src + 1;
  1775.         var = dst;
  1776.         c = dstlen - 1;
  1777.  
  1778. #ifdef UNIX
  1779.         /* Unix has ${var-name} type environment vars */
  1780.         if (*tail == '{' && !vim_isIDc('{'))
  1781.         {
  1782.             tail++;    /* ignore '{' */
  1783.             while (c-- > 0 && *tail && *tail != '}')
  1784.             *var++ = *tail++;
  1785.             tail++;    /* ignore '}' */
  1786.         }
  1787.         else
  1788. #endif
  1789.         {
  1790.             while (c-- > 0 && *tail && vim_isIDc(*tail))
  1791.             {
  1792. #ifdef OS2        /* env vars only in uppercase */
  1793.             *var++ = TO_UPPER(*tail);
  1794.             tail++;        /* toupper() may be a macro! */
  1795. #else
  1796.             *var++ = *tail++;
  1797. #endif
  1798.             }
  1799.         }
  1800.  
  1801.         *var = NUL;
  1802. #if defined(OS2) || defined(MSDOS) || defined(WIN32)
  1803.         /* use "C:/" when $HOME is not set */
  1804.         if (STRCMP(dst, "HOME") == 0)
  1805.             var = homedir;
  1806.         else
  1807. #endif
  1808.         {
  1809.             var = vim_getenv(dst);
  1810.             /*
  1811.              * When expanding $VIM fails, try using the directory name
  1812.              * from 'helpfile'.
  1813.              */
  1814.             if (var == NULL && STRCMP(dst, "VIM") == 0)
  1815.             {
  1816.             p = NULL;
  1817.             if (vim_strchr(p_hf, '$') == NULL)
  1818.                 p = p_hf;
  1819. #ifdef USE_EXE_NAME
  1820.             /*
  1821.              * Use the name of the executable, obtained from
  1822.              * argv[0].
  1823.              */
  1824.             else
  1825.             {
  1826.                 p = exe_name;
  1827. # ifdef MSDOS
  1828.                 /*
  1829.                  * Try the DOS search path.  The executable may in
  1830.                  * fact be called differently, so try this last.
  1831.                  */
  1832.                 if (p == NULL || *p == NUL)
  1833.                 p = searchpath("vim.exe");
  1834. # endif
  1835.             }
  1836. #endif
  1837.             if (p != NULL)
  1838.             {
  1839.                 char_u    *pend;
  1840.  
  1841.                 /* remove the file name */
  1842.                 pend = gettail(p);
  1843.                 /* remove "doc/" from 'helpfile', if present */
  1844.                 if (p == p_hf && pend - 4 >= p
  1845.                     && fnamencmp(pend - 4, "doc", 3) == 0
  1846.                     && (pend - 4 == p
  1847.                         || vim_ispathsep(pend[-5])))
  1848.                 pend -= 4;
  1849. #ifdef USE_EXE_NAME
  1850.                 /* remove "src/" from exe_name, if present */
  1851.                 if (p == exe_name)
  1852.                 {
  1853.                 if (pend - 4 >= p
  1854.                     && fnamencmp(pend - 4, "src", 3) == 0
  1855.                     && (pend - 4 == p
  1856.                         || vim_ispathsep(pend[-5])))
  1857.                     pend -= 4;
  1858.                 }
  1859. #endif
  1860. #ifndef macintosh
  1861.                 /* remove trailing path separator */
  1862.                 if (pend > p && vim_ispathsep(pend[-1]))
  1863.                 --pend;
  1864. #endif
  1865.                 var = vim_strnsave(p, (int)(pend - p));
  1866.                 mustfree = TRUE;
  1867.                 if (!mch_isdir(var))
  1868.                 {
  1869.                 vim_free(var);
  1870.                 var = NULL;
  1871.                 }
  1872.             }
  1873. #ifdef HAVE_PATHDEF
  1874.             /* for Unix we can use default_vim_dir */
  1875.             if (var == NULL)
  1876.             {
  1877.                 var = default_vim_dir;
  1878.                 mustfree = FALSE;
  1879.             }
  1880. #endif
  1881.             }
  1882.         }
  1883.         }
  1884.                             /* home directory */
  1885.         else if (  src[1] == NUL
  1886.             || vim_ispathsep(src[1])
  1887.             || vim_strchr((char_u *)" ,\t\n", src[1]) != NULL)
  1888.         {
  1889.         var = homedir;
  1890.         tail = src + 1;
  1891.         }
  1892.         else                    /* user directory */
  1893.         {
  1894. #ifndef UNIX
  1895.         /* cannot expand user's home directory, so don't try */
  1896.         var = NULL;
  1897.         tail = (char_u *)"";    /* for gcc */
  1898. #else
  1899.         /*
  1900.          * Copy ~user to dst[], so we can put a NUL after it.
  1901.          */
  1902.         tail = src;
  1903.         var = dst;
  1904.         c = dstlen - 1;
  1905.         while (       c-- > 0
  1906.             && *tail
  1907.             && vim_isfilec(*tail)
  1908.             && !vim_ispathsep(*tail))
  1909.             *var++ = *tail++;
  1910.         *var = NUL;
  1911.  
  1912.         /*
  1913.          * If the system supports getpwnam(), use it.
  1914.          * Otherwise, or if getpwnam() fails, the shell is used to
  1915.          * expand ~user.  This is slower and may fail if the shell
  1916.          * does not support ~user (old versions of /bin/sh).
  1917.          */
  1918. # if defined(HAVE_GETPWNAM) && defined(HAVE_PWD_H)
  1919.         {
  1920.             struct passwd *pw;
  1921.  
  1922.             pw = getpwnam((char *)dst + 1);
  1923.             if (pw != NULL)
  1924.             var = (char_u *)pw->pw_dir;
  1925.             else
  1926.             var = NULL;
  1927.         }
  1928.         if (var == NULL)
  1929. # endif
  1930.         {
  1931.             var = ExpandOne(dst, NULL, 0, WILD_EXPAND_FREE);
  1932.             mustfree = TRUE;
  1933.         }
  1934. #endif /* UNIX */
  1935.         }
  1936.  
  1937.         if (var != NULL && *var != NUL &&
  1938.               (STRLEN(var) + STRLEN(tail) + 1 < (unsigned)dstlen))
  1939.         {
  1940.         STRCPY(dst, var);
  1941.         dstlen -= STRLEN(var);
  1942.         dst += STRLEN(var);
  1943.             /* if var[] ends in a path separator and tail[] starts
  1944.              * with it, skip a character */
  1945.         if (*var && vim_ispathsep(*(dst-1)) && vim_ispathsep(*tail))
  1946.             ++tail;
  1947.         src = tail;
  1948.         copy_char = FALSE;
  1949.         }
  1950.         if (mustfree)
  1951.         vim_free(var);
  1952.     }
  1953.  
  1954.     if (copy_char)        /* copy at least one char */
  1955.     {
  1956.         /*
  1957.          * Recogize the start of a new name, for '~'.
  1958.          */
  1959.         at_start = FALSE;
  1960.         if (src[0] == '\\')
  1961.         {
  1962.         *dst++ = *src++;
  1963.         --dstlen;
  1964.         }
  1965.         else if (src[0] == ' ' || src[0] == ',')
  1966.         at_start = TRUE;
  1967.         *dst++ = *src++;
  1968.         --dstlen;
  1969.     }
  1970.     }
  1971.     *dst = NUL;
  1972. }
  1973.  
  1974. /*
  1975.  * Call expand_env() and store the result in an allocated string.
  1976.  * This is not very memory efficient, this expects the result to be freed
  1977.  * again soon.
  1978.  */
  1979.     char_u *
  1980. expand_env_save(src)
  1981.     char_u    *src;
  1982. {
  1983.     char_u    *p;
  1984.  
  1985.     p = alloc(MAXPATHL);
  1986.     if (p != NULL)
  1987.     expand_env(src, p, MAXPATHL);
  1988.     return p;
  1989. }
  1990.  
  1991. /*
  1992.  * Replace home directory by "~" in each space or comma separated file name in
  1993.  * 'src'.  If anything fails (except when out of space) dst equals src.
  1994.  */
  1995.     void
  1996. home_replace(buf, src, dst, dstlen)
  1997.     BUF        *buf;        /* when not NULL, check for help files */
  1998.     char_u  *src;        /* input file name */
  1999.     char_u  *dst;        /* where to put the result */
  2000.     int        dstlen;        /* maximum length of the result */
  2001. {
  2002.     size_t  dirlen = 0, envlen = 0;
  2003.     size_t  len;
  2004.     char_u  *homedir_env;
  2005.     char_u  *p;
  2006.  
  2007.     if (src == NULL)
  2008.     {
  2009.     *dst = NUL;
  2010.     return;
  2011.     }
  2012.  
  2013.     /*
  2014.      * If the file is a help file, remove the path completely.
  2015.      */
  2016.     if (buf != NULL && buf->b_help)
  2017.     {
  2018.     STRCPY(dst, gettail(src));
  2019.     return;
  2020.     }
  2021.  
  2022.     /*
  2023.      * We check both the value of the $HOME environment variable and the
  2024.      * "real" home directory.
  2025.      */
  2026.     if (homedir != NULL)
  2027.     dirlen = STRLEN(homedir);
  2028.     homedir_env = vim_getenv((char_u *)"HOME");
  2029.     if (homedir_env != NULL)
  2030.     envlen = STRLEN(homedir_env);
  2031.  
  2032.     src = skipwhite(src);
  2033.     while (*src && dstlen > 0)
  2034.     {
  2035.     /*
  2036.      * Here we are at the beginning of a file name.
  2037.      * First, check to see if the beginning of the file name matches
  2038.      * $HOME or the "real" home directory. Check that there is a '/'
  2039.      * after the match (so that if e.g. the file is "/home/pieter/bla",
  2040.      * and the home directory is "/home/piet", the file does not end up
  2041.      * as "~er/bla" (which would seem to indicate the file "bla" in user
  2042.      * er's home directory)).
  2043.      */
  2044.     p = homedir;
  2045.     len = dirlen;
  2046.     for (;;)
  2047.     {
  2048.         if (   len
  2049.         && fnamencmp(src, p, len) == 0
  2050.         && (vim_ispathsep(src[len])
  2051.             || src[len] == ','
  2052.             || src[len] == ' '
  2053.             || src[len] == NUL))
  2054.         {
  2055.         src += len;
  2056.         if (--dstlen > 0)
  2057.             *dst++ = '~';
  2058.  
  2059.         /*
  2060.          * If it's just the home directory, add  "/".
  2061.          */
  2062.         if (!vim_ispathsep(src[0]) && --dstlen > 0)
  2063.             *dst++ = '/';
  2064.         }
  2065.         if (p == homedir_env)
  2066.         break;
  2067.         p = homedir_env;
  2068.         len = envlen;
  2069.     }
  2070.  
  2071.     /* skip to separator: space or comma */
  2072.     while (*src && *src != ',' && *src != ' ' && --dstlen > 0)
  2073.         *dst++ = *src++;
  2074.     /* skip separator */
  2075.     while ((*src == ' ' || *src == ',') && --dstlen > 0)
  2076.         *dst++ = *src++;
  2077.     }
  2078.     /* if (dstlen == 0) out of space, what to do??? */
  2079.  
  2080.     *dst = NUL;
  2081. }
  2082.  
  2083. /*
  2084.  * Like home_replace, store the replaced string in allocated memory.
  2085.  * When something fails, NULL is returned.
  2086.  */
  2087.     char_u  *
  2088. home_replace_save(buf, src)
  2089.     BUF        *buf;        /* when not NULL, check for help files */
  2090.     char_u  *src;        /* input file name */
  2091. {
  2092.     char_u    *dst;
  2093.     unsigned    len;
  2094.  
  2095.     len = 3;            /* space for "~/" and trailing NUL */
  2096.     if (src != NULL)        /* just in case */
  2097.     len += STRLEN(src);
  2098.     dst = alloc(len);
  2099.     if (dst != NULL)
  2100.     home_replace(buf, src, dst, len);
  2101.     return dst;
  2102. }
  2103.  
  2104. /*
  2105.  * Compare two file names and return:
  2106.  * FPC_SAME   if they both exist and are the same file.
  2107.  * FPC_SAMEX  if they both don't exist and have the same file name.
  2108.  * FPC_DIFF   if they both exist and are different files.
  2109.  * FPC_NOTX   if they both don't exist.
  2110.  * FPC_DIFFX  if one of them doesn't exist.
  2111.  * For the first name environment variables are expanded
  2112.  */
  2113.     int
  2114. fullpathcmp(s1, s2, checkname)
  2115.     char_u *s1, *s2;
  2116.     int        checkname;        /* when both don't exist, check file names */
  2117. {
  2118. #ifdef UNIX
  2119.     char_u        exp1[MAXPATHL];
  2120.     char_u        full1[MAXPATHL];
  2121.     char_u        full2[MAXPATHL];
  2122.     struct stat        st1, st2;
  2123.     int            r1, r2;
  2124.  
  2125.     expand_env(s1, exp1, MAXPATHL);
  2126.     r1 = stat((char *)exp1, &st1);
  2127.     r2 = stat((char *)s2, &st2);
  2128.     if (r1 != 0 && r2 != 0)
  2129.     {
  2130.     /* if stat() doesn't work, may compare the names */
  2131.     if (checkname)
  2132.     {
  2133.         if (fnamecmp(exp1, s2) == 0)
  2134.         return FPC_SAMEX;
  2135.         r1 = mch_FullName(exp1, full1, MAXPATHL, FALSE);
  2136.         r2 = mch_FullName(s2, full2, MAXPATHL, FALSE);
  2137.         if (r1 == OK && r2 == OK && fnamecmp(full1, full2) == 0)
  2138.         return FPC_SAMEX;
  2139.     }
  2140.     return FPC_NOTX;
  2141.     }
  2142.     if (r1 != 0 || r2 != 0)
  2143.     return FPC_DIFFX;
  2144.     if (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino)
  2145.     return FPC_SAME;
  2146.     return FPC_DIFF;
  2147. #else
  2148.     char_u  *exp1;        /* expanded s1 */
  2149.     char_u  *full1;        /* full path of s1 */
  2150.     char_u  *full2;        /* full path of s2 */
  2151.     int        retval = FPC_DIFF;
  2152.     int        r1, r2;
  2153.  
  2154.     /* allocate one buffer to store three paths (alloc()/free() is slow!) */
  2155.     if ((exp1 = alloc(MAXPATHL * 3)) != NULL)
  2156.     {
  2157.     full1 = exp1 + MAXPATHL;
  2158.     full2 = full1 + MAXPATHL;
  2159.  
  2160.     expand_env(s1, exp1, MAXPATHL);
  2161.     r1 = mch_FullName(exp1, full1, MAXPATHL, FALSE);
  2162.     r2 = mch_FullName(s2, full2, MAXPATHL, FALSE);
  2163.  
  2164.     /* If mch_FullName() fails, the file probably doesn't exist. */
  2165.     if (r1 != OK && r2 != OK)
  2166.     {
  2167.         if (checkname && fnamecmp(exp1, s2) == 0)
  2168.         return FPC_SAMEX;
  2169.         retval = FPC_NOTX;
  2170.     }
  2171.     else if (r1 != OK || r2 != OK)
  2172.         retval = FPC_DIFFX;
  2173.     else if (fnamecmp(full1, full2))
  2174.         retval = FPC_DIFF;
  2175.     else
  2176.         retval = FPC_SAME;
  2177.     }
  2178.     vim_free(exp1);
  2179.     return retval;
  2180. #endif
  2181. }
  2182.  
  2183. /*
  2184.  * get the tail of a path: the file name.
  2185.  */
  2186.     char_u *
  2187. gettail(fname)
  2188.     char_u *fname;
  2189. {
  2190.     char_u  *p1, *p2;
  2191.  
  2192.     if (fname == NULL)
  2193.     return (char_u *)"";
  2194.     for (p1 = p2 = fname; *p2; ++p2)    /* find last part of path */
  2195.     {
  2196.     if (vim_ispathsep(*p2))
  2197.         p1 = p2 + 1;
  2198.     }
  2199.     return p1;
  2200. }
  2201.  
  2202. /*
  2203.  * get the next path component (just after the next path separator).
  2204.  */
  2205.     char_u *
  2206. getnextcomp(fname)
  2207.     char_u *fname;
  2208. {
  2209.     while (*fname && !vim_ispathsep(*fname))
  2210.     ++fname;
  2211.     if (*fname)
  2212.     ++fname;
  2213.     return fname;
  2214. }
  2215.  
  2216. /*
  2217.  * Get a pointer to one character past the head of a path name.
  2218.  * Unix: after "/"; DOS: after "c:\"; Amiga: after "disk:/"; Mac: no head.
  2219.  * If there is no head, path is returned.
  2220.  */
  2221.     char_u *
  2222. get_past_head(path)
  2223.     char_u  *path;
  2224. {
  2225.     char_u  *retval;
  2226.  
  2227. #if defined(MSDOS) || defined(WIN32) || defined(OS2)
  2228.     /* may skip "c:" */
  2229.     if (isalpha(path[0]) && path[1] == ':')
  2230.     retval = path + 2;
  2231.     else
  2232.     retval = path;
  2233. #else
  2234. # if defined(AMIGA)
  2235.     /* may skip "label:" */
  2236.     retval = vim_strchr(path, ':');
  2237.     if (retval == NULL)
  2238.     retval = path;
  2239. # else    /* Unix */
  2240.     retval = path;
  2241. # endif
  2242. #endif
  2243.  
  2244.     while (vim_ispathsep(*retval))
  2245.     ++retval;
  2246.  
  2247.     return retval;
  2248. }
  2249.  
  2250. /*
  2251.  * return TRUE if 'c' is a path separator.
  2252.  */
  2253.     int
  2254. vim_ispathsep(c)
  2255.     int c;
  2256. {
  2257. #ifdef UNIX
  2258.     return (c == '/');        /* UNIX has ':' inside file names */
  2259. #else
  2260. # ifdef BACKSLASH_IN_FILENAME
  2261.     return (c == ':' || c == '/' || c == '\\');
  2262. # else
  2263. #  ifdef COLON_AS_PATHSEP
  2264.     return (c == ':');
  2265. #  else    /* Amiga */
  2266.     return (c == ':' || c == '/');
  2267. #  endif
  2268. # endif
  2269. #endif
  2270. }
  2271.  
  2272. /*
  2273.  * Concatenate file names fname1 and fname2 into allocated memory.
  2274.  * Only add a '/' or '\\' when 'sep' is TRUE and it is neccesary.
  2275.  */
  2276.     char_u  *
  2277. concat_fnames(fname1, fname2, sep)
  2278.     char_u  *fname1;
  2279.     char_u  *fname2;
  2280.     int        sep;
  2281. {
  2282.     char_u  *dest;
  2283.  
  2284.     dest = alloc((unsigned)(STRLEN(fname1) + STRLEN(fname2) + 3));
  2285.     if (dest != NULL)
  2286.     {
  2287.     STRCPY(dest, fname1);
  2288.     if (sep && *dest && !vim_ispathsep(*(dest + STRLEN(dest) - 1)))
  2289.         STRCAT(dest, PATHSEPSTR);
  2290.     STRCAT(dest, fname2);
  2291.     }
  2292.     return dest;
  2293. }
  2294.  
  2295. /*
  2296.  * FullName_save - Make an allocated copy of a full file name.
  2297.  * Returns NULL when out of memory.
  2298.  */
  2299.     char_u  *
  2300. FullName_save(fname, force)
  2301.     char_u    *fname;
  2302.     int        force;        /* force expansion, even when it already looks
  2303.                    like a full path name */
  2304. {
  2305.     char_u    *buf;
  2306.     char_u    *new_fname = NULL;
  2307.  
  2308.     buf = alloc((unsigned)MAXPATHL);
  2309.     if (buf != NULL)
  2310.     {
  2311.     if (mch_FullName(fname, buf, MAXPATHL, force) != FAIL)
  2312.         new_fname = vim_strsave(buf);
  2313.     else
  2314.         new_fname = vim_strsave(fname);
  2315.     vim_free(buf);
  2316.     }
  2317.     return new_fname;
  2318. }
  2319.  
  2320. #ifdef CINDENT
  2321.  
  2322. /*
  2323.  * Functions for C-indenting.
  2324.  * Most of this originally comes from Eric Fischer.
  2325.  */
  2326. /*
  2327.  * Below "XXX" means that this function may unlock the current line.
  2328.  */
  2329.  
  2330. static int    cin_isdefault __ARGS((char_u *));
  2331. static char_u    *after_label __ARGS((char_u *l));
  2332. static int    get_indent_nolabel __ARGS((linenr_t lnum));
  2333. static int    skip_label __ARGS((linenr_t, char_u **pp, int ind_maxcomment));
  2334. static int    cin_ispreproc __ARGS((char_u *));
  2335. static int    cin_iscomment __ARGS((char_u *));
  2336. static int    commentorempty __ARGS((char_u *));
  2337. static int    cin_isterminated __ARGS((char_u *, int));
  2338. static int    cin_isfuncdecl __ARGS((char_u *));
  2339. static char_u    *skip_string __ARGS((char_u *p));
  2340. static int    cin_isif __ARGS((char_u *));
  2341. static int    cin_iselse __ARGS((char_u *));
  2342. static int    cin_isdo __ARGS((char_u *));
  2343. static int    cin_iswhileofdo __ARGS((char_u *, linenr_t, int));
  2344. static FPOS    *find_start_brace __ARGS((int));
  2345. static FPOS    *find_match_paren __ARGS((int, int));
  2346. static int    find_last_paren __ARGS((char_u *l));
  2347. static int    find_match __ARGS((int lookfor, linenr_t ourscope,
  2348.             int ind_maxparen, int ind_maxcomment));
  2349.  
  2350. /*
  2351.  * Recognize a label: "label:".
  2352.  * Note: curwin->w_cursor must be where we are looking for the label.
  2353.  */
  2354.     int
  2355. cin_islabel(ind_maxcomment)        /* XXX */
  2356.     int        ind_maxcomment;
  2357. {
  2358.     char_u    *s;
  2359.  
  2360.     s = skipwhite(ml_get_curline());
  2361.  
  2362.     /*
  2363.      * Exclude "default" from labels, since it should be indented
  2364.      * like a switch label.  Same for C++ scope declarations.
  2365.      */
  2366.     if (cin_isdefault(s))
  2367.     return FALSE;
  2368.     if (cin_isscopedecl(s))
  2369.     return FALSE;
  2370.  
  2371.     if (!vim_isIDc(*s))        /* need at least one ID character */
  2372.     return FALSE;
  2373.  
  2374.     while (vim_isIDc(*s))
  2375.     s++;
  2376.  
  2377.     s = skipwhite(s);
  2378.  
  2379.     /* "::" is not a label, it's C++ */
  2380.     if (*s == ':' && s[1] != ':')
  2381.     {
  2382.     /*
  2383.      * Only accept a label if the previous line is terminated or is a case
  2384.      * label.
  2385.      */
  2386.     FPOS    cursor_save;
  2387.     FPOS    *trypos;
  2388.     char_u    *line;
  2389.  
  2390.     cursor_save = curwin->w_cursor;
  2391.     while (curwin->w_cursor.lnum > 1)
  2392.     {
  2393.         --curwin->w_cursor.lnum;
  2394.  
  2395.         /*
  2396.          * If we're in a comment now, skip to the start of the comment.
  2397.          */
  2398.         curwin->w_cursor.col = 0;
  2399.         if ((trypos = find_start_comment(ind_maxcomment)) != NULL) /* XXX */
  2400.         curwin->w_cursor = *trypos;
  2401.  
  2402.         line = ml_get_curline();
  2403.         if (cin_ispreproc(line))    /* ignore #defines, #if, etc. */
  2404.         continue;
  2405.         if (commentorempty(line))
  2406.         continue;
  2407.  
  2408.         curwin->w_cursor = cursor_save;
  2409.         if (cin_isterminated(line, TRUE) || cin_isscopedecl(line)
  2410.                               || cin_iscase(line))
  2411.         return TRUE;
  2412.         return FALSE;
  2413.     }
  2414.     curwin->w_cursor = cursor_save;
  2415.     return TRUE;        /* label at start of file??? */
  2416.     }
  2417.     return FALSE;
  2418. }
  2419.  
  2420. /*
  2421.  * Recognize a switch label: "case .*:" or "default:".
  2422.  */
  2423.      int
  2424. cin_iscase(s)
  2425.     char_u *s;
  2426. {
  2427.     s = skipwhite(s);
  2428.     if (STRNCMP(s, "case", 4) == 0 && !vim_isIDc(s[4]))
  2429.     {
  2430.     for (s += 4; *s; ++s)
  2431.         if (*s == ':')
  2432.         {
  2433.         if (s[1] == ':')    /* skip over "::" for C++ */
  2434.             ++s;
  2435.         else
  2436.             return TRUE;
  2437.         }
  2438.     return FALSE;
  2439.     }
  2440.  
  2441.     if (cin_isdefault(s))
  2442.     return TRUE;
  2443.     return FALSE;
  2444. }
  2445.  
  2446. /*
  2447.  * Recognize a "default" switch label.
  2448.  */
  2449.     static int
  2450. cin_isdefault(s)
  2451.     char_u  *s;
  2452. {
  2453.     return (STRNCMP(s, "default", 7) == 0 &&
  2454.         *(s = skipwhite(s + 7)) == ':' &&
  2455.         s[1] != ':');
  2456. }
  2457.  
  2458. /*
  2459.  * Recognize a "public/private/proctected" scope declaration label.
  2460.  */
  2461.     int
  2462. cin_isscopedecl(s)
  2463.     char_u    *s;
  2464. {
  2465.     int        i;
  2466.  
  2467.     s = skipwhite(s);
  2468.     if (STRNCMP(s, "public", 6) == 0)
  2469.     i = 6;
  2470.     else if (STRNCMP(s, "protected", 9) == 0)
  2471.     i = 9;
  2472.     else if (STRNCMP(s, "private", 7) == 0)
  2473.     i = 7;
  2474.     else
  2475.     return FALSE;
  2476.     return (*(s = skipwhite(s + i)) == ':' && s[1] != ':');
  2477. }
  2478.  
  2479. /*
  2480.  * Return a pointer to the first non-empty non-comment character after a ':'.
  2481.  * Return NULL if not found.
  2482.  *      case 234:    a = b;
  2483.  *               ^
  2484.  */
  2485.     static char_u *
  2486. after_label(l)
  2487.     char_u  *l;
  2488. {
  2489.     for ( ; *l; ++l)
  2490.     if (*l == ':')
  2491.     {
  2492.         if (l[1] == ':')        /* skip over "::" for C++ */
  2493.         ++l;
  2494.         else
  2495.         break;
  2496.     }
  2497.     if (*l == NUL)
  2498.     return NULL;
  2499.     l = skipwhite(l + 1);
  2500.     if (commentorempty(l))
  2501.     return NULL;
  2502.     return l;
  2503. }
  2504.  
  2505. /*
  2506.  * Get indent of line "lnum", skipping a label.
  2507.  * Return 0 if there is nothing after the label.
  2508.  */
  2509.     static int
  2510. get_indent_nolabel(lnum)        /* XXX */
  2511.     linenr_t    lnum;
  2512. {
  2513.     char_u    *l;
  2514.     FPOS    fp;
  2515.     colnr_t    col;
  2516.     char_u    *p;
  2517.  
  2518.     l = ml_get(lnum);
  2519.     p = after_label(l);
  2520.     if (p == NULL)
  2521.     return 0;
  2522.  
  2523.     fp.col = p - l;
  2524.     fp.lnum = lnum;
  2525.     getvcol(curwin, &fp, &col, NULL, NULL);
  2526.     return (int)col;
  2527. }
  2528.  
  2529. /*
  2530.  * Find indent for line "lnum", ignoring any case or jump label.
  2531.  * Also return a pointer to the text (after the label).
  2532.  *   label:    if (asdf && asdfasdf)
  2533.  *        ^
  2534.  */
  2535.     static int
  2536. skip_label(lnum, pp, ind_maxcomment)
  2537.     linenr_t    lnum;
  2538.     char_u    **pp;
  2539.     int        ind_maxcomment;
  2540. {
  2541.     char_u    *l;
  2542.     int        amount;
  2543.     FPOS    cursor_save;
  2544.  
  2545.     cursor_save = curwin->w_cursor;
  2546.     curwin->w_cursor.lnum = lnum;
  2547.     l = ml_get_curline();
  2548.                     /* XXX */
  2549.     if (cin_iscase(l) || cin_isscopedecl(l) || cin_islabel(ind_maxcomment))
  2550.     {
  2551.     amount = get_indent_nolabel(lnum);
  2552.     l = after_label(ml_get_curline());
  2553.     if (l == NULL)        /* just in case */
  2554.         l = ml_get_curline();
  2555.     }
  2556.     else
  2557.     {
  2558.     amount = get_indent();
  2559.     l = ml_get_curline();
  2560.     }
  2561.     *pp = l;
  2562.  
  2563.     curwin->w_cursor = cursor_save;
  2564.     return amount;
  2565. }
  2566.  
  2567. /*
  2568.  * Recognize a preprocessor statement: Any line that starts with '#'.
  2569.  */
  2570.     static int
  2571. cin_ispreproc(s)
  2572.     char_u *s;
  2573. {
  2574.     s = skipwhite(s);
  2575.     if (*s == '#')
  2576.     return TRUE;
  2577.     return 0;
  2578. }
  2579.  
  2580. /*
  2581.  * Recognize the start of a C or C++ comment.
  2582.  */
  2583.     static int
  2584. cin_iscomment(p)
  2585.     char_u  *p;
  2586. {
  2587.     return (p[0] == '/' && (p[1] == '*' || p[1] == '/'));
  2588. }
  2589.  
  2590. /*
  2591.  * Recognize an empty or comment line.
  2592.  */
  2593.     static int
  2594. commentorempty(s)
  2595.     char_u *s;
  2596. {
  2597.     s = skipwhite(s);
  2598.     if (*s == NUL || cin_iscomment(s))
  2599.     return TRUE;
  2600.     return FALSE;
  2601. }
  2602.  
  2603. /*
  2604.  * Recognize a line that starts with '{' or '}', or ends with ';', '{' or '}'.
  2605.  * Don't consider "} else" a terminated line.
  2606.  * Also consider a line terminated if it ends in ','.  This is not 100%
  2607.  * correct, but this mostly means we are in initializations and then it's OK.
  2608.  */
  2609.     static int
  2610. cin_isterminated(s, incl_open)
  2611.     char_u    *s;
  2612.     int        incl_open;    /* include '{' at the end as terminator */
  2613. {
  2614.     s = skipwhite(s);
  2615.  
  2616.     if (*s == '{' || (*s == '}' && !cin_iselse(s)))
  2617.     return TRUE;
  2618.  
  2619.     while (*s)
  2620.     {
  2621.     if (cin_iscomment(s))    /* at start of comment ignore rest of line */
  2622.         return FALSE;
  2623.     s = skip_string(s);
  2624.     if ((*s == ';' || (incl_open && *s == '{') || *s == '}' || *s == ',')
  2625.                              && commentorempty(s + 1))
  2626.         return TRUE;
  2627.     s++;
  2628.     }
  2629.     return FALSE;
  2630. }
  2631.  
  2632. /*
  2633.  * Recognize the basic picture of a function declaration -- it needs to
  2634.  * have an open paren somewhere and a close paren at the end of the line and
  2635.  * no semicolons anywhere.
  2636.  */
  2637.     static int
  2638. cin_isfuncdecl(s)
  2639.     char_u *s;
  2640. {
  2641.     while (*s && *s != '(' && *s != ';')
  2642.     if (cin_iscomment(s++))
  2643.         return FALSE;        /* comment before () ??? */
  2644.     if (*s != '(')
  2645.     return FALSE;            /* ';' before any () or no '(' */
  2646.  
  2647.     while (*s && *s != ';')
  2648.     {
  2649.     if (*s == ')' && commentorempty(s + 1))
  2650.         return TRUE;
  2651.     if (cin_iscomment(s++))
  2652.         return FALSE;        /* comment between ( and ) ??? */
  2653.     }
  2654.     return FALSE;
  2655. }
  2656.  
  2657. /*
  2658.  * Skip over a "string" and a 'c' character.
  2659.  */
  2660.     static char_u *
  2661. skip_string(p)
  2662.     char_u  *p;
  2663. {
  2664.     int        i;
  2665.  
  2666.     /*
  2667.      * We loop, because strings may be concatenated: "date""time".
  2668.      */
  2669.     for ( ; ; ++p)
  2670.     {
  2671.     if (p[0] == '\'')            /* 'c' or '\n' or '\000' */
  2672.     {
  2673.         if (!p[1])                /* ' at end of line */
  2674.         break;
  2675.         i = 2;
  2676.         if (p[1] == '\\')            /* '\n' or '\000' */
  2677.         {
  2678.         ++i;
  2679.         while (isdigit(p[i - 1]))   /* '\000' */
  2680.             ++i;
  2681.         }
  2682.         if (p[i] == '\'')            /* check for trailing ' */
  2683.         {
  2684.         p += i;
  2685.         continue;
  2686.         }
  2687.     }
  2688.     else if (p[0] == '"')            /* start of string */
  2689.     {
  2690.         for (++p; p[0]; ++p)
  2691.         {
  2692.         if (p[0] == '\\' && p[1])
  2693.             ++p;
  2694.         else if (p[0] == '"')        /* end of string */
  2695.             break;
  2696.         }
  2697.         continue;
  2698.     }
  2699.     break;                    /* no string found */
  2700.     }
  2701.     if (!*p)
  2702.     --p;                    /* backup from NUL */
  2703.     return p;
  2704. }
  2705.  
  2706.     static int
  2707. cin_isif(p)
  2708.     char_u  *p;
  2709. {
  2710.     return (STRNCMP(p, "if", 2) == 0 && !vim_isIDc(p[2]));
  2711. }
  2712.  
  2713.     static int
  2714. cin_iselse(p)
  2715.     char_u  *p;
  2716. {
  2717.     if (*p == '}')        /* accept "} else" */
  2718.     p = skipwhite(p + 1);
  2719.     return (STRNCMP(p, "else", 4) == 0 && !vim_isIDc(p[4]));
  2720. }
  2721.  
  2722.     static int
  2723. cin_isdo(p)
  2724.     char_u  *p;
  2725. {
  2726.     return (STRNCMP(p, "do", 2) == 0 && !vim_isIDc(p[2]));
  2727. }
  2728.  
  2729. /*
  2730.  * Check if this is a "while" that should have a matching "do".
  2731.  * We only accept a "while (condition) ;", with only white space between the
  2732.  * ')' and ';'. The condition may be spread over several lines.
  2733.  */
  2734.     static int
  2735. cin_iswhileofdo(p, lnum, ind_maxparen)        /* XXX */
  2736.     char_u    *p;
  2737.     linenr_t    lnum;
  2738.     int        ind_maxparen;
  2739. {
  2740.     FPOS    cursor_save;
  2741.     FPOS    *trypos;
  2742.     int        retval = FALSE;
  2743.  
  2744.     p = skipwhite(p);
  2745.     if (*p == '}')        /* accept "} while (cond);" */
  2746.     p = skipwhite(p + 1);
  2747.     if (STRNCMP(p, "while", 5) == 0 && !vim_isIDc(p[5]))
  2748.     {
  2749.     cursor_save = curwin->w_cursor;
  2750.     curwin->w_cursor.lnum = lnum;
  2751.     curwin->w_cursor.col = 0;
  2752.     p = ml_get_curline();
  2753.     while (*p && *p != 'w')    /* skip any '}', until the 'w' of the "while" */
  2754.     {
  2755.         ++p;
  2756.         ++curwin->w_cursor.col;
  2757.     }
  2758.     if ((trypos = findmatchlimit(NULL, 0, 0, ind_maxparen)) != NULL)
  2759.     {
  2760.         p = ml_get_pos(trypos) + 1;
  2761.         p = skipwhite(p);
  2762.         if (*p == ';')
  2763.         retval = TRUE;
  2764.     }
  2765.     curwin->w_cursor = cursor_save;
  2766.     }
  2767.     return retval;
  2768. }
  2769.  
  2770. /*
  2771.  * Find the start of a comment, not knowing if we are in a comment right now.
  2772.  * Search starts at w_cursor.lnum and goes backwards.
  2773.  */
  2774.     FPOS *
  2775. find_start_comment(ind_maxcomment)        /* XXX */
  2776.     int        ind_maxcomment;
  2777. {
  2778.     FPOS    *pos;
  2779.     char_u    *line;
  2780.     char_u    *p;
  2781.  
  2782.     if ((pos = findmatchlimit(NULL, '*', FM_BACKWARD, ind_maxcomment)) == NULL)
  2783.     return NULL;
  2784.  
  2785.     /*
  2786.      * Check if the comment start we found is inside a string.
  2787.      */
  2788.     line = ml_get(pos->lnum);
  2789.     for (p = line; *p && (unsigned)(p - line) < pos->col; ++p)
  2790.     p = skip_string(p);
  2791.     if ((unsigned)(p - line) > pos->col)
  2792.     return NULL;
  2793.     return pos;
  2794. }
  2795.  
  2796. /*
  2797.  * Find the '{' at the start of the block we are in.
  2798.  * Return NULL of no match found.
  2799.  * Ignore a '{' that is in a comment, makes indenting the next three lines
  2800.  * work. */
  2801. /* foo()    */
  2802. /* {        */
  2803. /* }        */
  2804.  
  2805.     static FPOS *
  2806. find_start_brace(ind_maxcomment)        /* XXX */
  2807.     int        ind_maxcomment;
  2808. {
  2809.     FPOS    cursor_save;
  2810.     FPOS    *trypos;
  2811.     FPOS    *pos;
  2812.     static FPOS    pos_copy;
  2813.  
  2814.     cursor_save = curwin->w_cursor;
  2815.     while ((trypos = findmatchlimit(NULL, '{', FM_BLOCKSTOP, 0)) != NULL)
  2816.     {
  2817.     pos_copy = *trypos;    /* copy FPOS, next findmatch will change it */
  2818.     trypos = &pos_copy;
  2819.     curwin->w_cursor = *trypos;
  2820.     pos = NULL;
  2821.     if (!cin_iscomment(skipwhite(ml_get(trypos->lnum))) &&
  2822.          (pos = find_start_comment(ind_maxcomment)) == NULL) /* XXX */
  2823.         break;
  2824.     if (pos != NULL)
  2825.         curwin->w_cursor.lnum = pos->lnum;
  2826.     }
  2827.     curwin->w_cursor = cursor_save;
  2828.     return trypos;
  2829. }
  2830.  
  2831. /*
  2832.  * Find the matching '(', failing if it is in a comment.
  2833.  * Return NULL of no match found.
  2834.  */
  2835.     static FPOS *
  2836. find_match_paren(ind_maxparen, ind_maxcomment)        /* XXX */
  2837.     int        ind_maxparen;
  2838.     int        ind_maxcomment;
  2839. {
  2840.     FPOS    cursor_save;
  2841.     FPOS    *trypos;
  2842.     static FPOS    pos_copy;
  2843.  
  2844.     cursor_save = curwin->w_cursor;
  2845.     if ((trypos = findmatchlimit(NULL, '(', 0, ind_maxparen)) != NULL)
  2846.     {
  2847.     if (cin_iscomment(skipwhite(ml_get(trypos->lnum))))
  2848.         trypos = NULL;
  2849.     else
  2850.     {
  2851.         pos_copy = *trypos;        /* copy trypos, findmatch will change it */
  2852.         trypos = &pos_copy;
  2853.         curwin->w_cursor = *trypos;
  2854.         if (find_start_comment(ind_maxcomment) != NULL) /* XXX */
  2855.         trypos = NULL;
  2856.     }
  2857.     }
  2858.     curwin->w_cursor = cursor_save;
  2859.     return trypos;
  2860. }
  2861.  
  2862. /*
  2863.  * Set w_cursor.col to the column number of the last ')' in line "l".
  2864.  */
  2865.     static int
  2866. find_last_paren(l)
  2867.     char_u *l;
  2868. {
  2869.     int        i;
  2870.     int        retval = FALSE;
  2871.  
  2872.     curwin->w_cursor.col = 0;            /* default is start of line */
  2873.  
  2874.     for (i = 0; l[i]; i++)
  2875.     {
  2876.     i = skip_string(l + i) - l;        /* ignore parens in quotes */
  2877.     if (l[i] == ')')
  2878.     {
  2879.         curwin->w_cursor.col = i;
  2880.         retval = TRUE;
  2881.     }
  2882.     }
  2883.     return retval;
  2884. }
  2885.  
  2886.     int
  2887. get_c_indent()
  2888. {
  2889.     /*
  2890.      * spaces from a block's opening brace the prevailing indent for that
  2891.      * block should be
  2892.      */
  2893.     int ind_level = curbuf->b_p_sw;
  2894.  
  2895.     /*
  2896.      * spaces from the edge of the line an open brace that's at the end of a
  2897.      * line is imagined to be.
  2898.      */
  2899.     int ind_open_imag = 0;
  2900.  
  2901.     /*
  2902.      * spaces from the prevailing indent for a line that is not precededof by
  2903.      * an opening brace.
  2904.      */
  2905.     int ind_no_brace = 0;
  2906.  
  2907.     /*
  2908.      * column where the first { of a function should be located }
  2909.      */
  2910.     int ind_first_open = 0;
  2911.  
  2912.     /*
  2913.      * spaces from the prevailing indent a leftmost open brace should be
  2914.      * located
  2915.      */
  2916.     int ind_open_extra = 0;
  2917.  
  2918.     /*
  2919.      * spaces from the matching open brace (real location for one at the left
  2920.      * edge; imaginary location from one that ends a line) the matching close
  2921.      * brace should be located
  2922.      */
  2923.     int ind_close_extra = 0;
  2924.  
  2925.     /*
  2926.      * spaces from the edge of the line an open brace sitting in the leftmost
  2927.      * column is imagined to be
  2928.      */
  2929.     int ind_open_left_imag = 0;
  2930.  
  2931.     /*
  2932.      * spaces from the switch() indent a "case xx" label should be located
  2933.      */
  2934.     int ind_case = curbuf->b_p_sw;
  2935.  
  2936.     /*
  2937.      * spaces from the "case xx:" code after a switch() should be located
  2938.      */
  2939.     int ind_case_code = curbuf->b_p_sw;
  2940.  
  2941.     /*
  2942.      * spaces from the class declaration indent a scope declaration label
  2943.      * should be located
  2944.      */
  2945.     int ind_scopedecl = curbuf->b_p_sw;
  2946.  
  2947.     /*
  2948.      * spaces from the scope declaration label code should be located
  2949.      */
  2950.     int ind_scopedecl_code = curbuf->b_p_sw;
  2951.  
  2952.     /*
  2953.      * amount K&R-style parameters should be indented
  2954.      */
  2955.     int ind_param = curbuf->b_p_sw;
  2956.  
  2957.     /*
  2958.      * amount a function type spec should be indented
  2959.      */
  2960.     int ind_func_type = curbuf->b_p_sw;
  2961.  
  2962.     /*
  2963.      * additional spaces beyond the prevailing indent a continuation line
  2964.      * should be located
  2965.      */
  2966.     int ind_continuation = curbuf->b_p_sw;
  2967.  
  2968.     /*
  2969.      * spaces from the indent of the line with an unclosed parentheses
  2970.      */
  2971.     int ind_unclosed = curbuf->b_p_sw * 2;
  2972.  
  2973.     /*
  2974.      * spaces from the indent of the line with an unclosed parentheses, which
  2975.      * itself is also unclosed
  2976.      */
  2977.     int ind_unclosed2 = curbuf->b_p_sw;
  2978.  
  2979.     /*
  2980.      * spaces from the comment opener when there is nothing after it.
  2981.      */
  2982.     int ind_in_comment = 3;
  2983.  
  2984.     /*
  2985.      * max lines to search for an open paren
  2986.      */
  2987.     int ind_maxparen = 20;
  2988.  
  2989.     /*
  2990.      * max lines to search for an open comment
  2991.      */
  2992.     int ind_maxcomment = 30;
  2993.  
  2994.     FPOS    cur_curpos;
  2995.     int        amount;
  2996.     int        scope_amount;
  2997.     int        cur_amount;
  2998.     colnr_t    col;
  2999.     char_u    *theline;
  3000.     char_u    *linecopy;
  3001.     FPOS    *trypos;
  3002.     FPOS    our_paren_pos;
  3003.     char_u    *start;
  3004.     int        start_brace;
  3005. #define BRACE_IN_COL0        1        /* '{' is in comumn 0 */
  3006. #define BRACE_AT_START        2        /* '{' is at start of line */
  3007. #define BRACE_AT_END        3        /* '{' is at end of line */
  3008.     linenr_t    ourscope;
  3009.     char_u    *l;
  3010.     char_u    *look;
  3011.     int        lookfor;
  3012. #define LOOKFOR_IF        1
  3013. #define LOOKFOR_DO        2
  3014. #define LOOKFOR_CASE        3
  3015. #define LOOKFOR_ANY        4
  3016. #define LOOKFOR_TERM        5
  3017. #define LOOKFOR_UNTERM        6
  3018. #define LOOKFOR_SCOPEDECL    7
  3019.     int        whilelevel;
  3020.     linenr_t    lnum;
  3021.     char_u    *options;
  3022.     int        fraction = 0;        /* init for GCC */
  3023.     int        divider;
  3024.     int        n;
  3025.     int        iscase;
  3026.  
  3027.     for (options = curbuf->b_p_cino; *options; )
  3028.     {
  3029.     l = options++;
  3030.     if (*options == '-')
  3031.         ++options;
  3032.     n = getdigits(&options);
  3033.     divider = 0;
  3034.     if (*options == '.')        /* ".5s" means a fraction */
  3035.     {
  3036.         fraction = atol((char *)++options);
  3037.         while (isdigit(*options))
  3038.         {
  3039.         ++options;
  3040.         if (divider)
  3041.             divider *= 10;
  3042.         else
  3043.             divider = 10;
  3044.         }
  3045.     }
  3046.     if (*options == 's')        /* "2s" means two times 'shiftwidth' */
  3047.     {
  3048.         if (n == 0 && fraction == 0)
  3049.         n = curbuf->b_p_sw;    /* just "s" is one 'shiftwidth' */
  3050.         else
  3051.         {
  3052.         n *= curbuf->b_p_sw;
  3053.         if (divider)
  3054.             n += (curbuf->b_p_sw * fraction + divider / 2) / divider;
  3055.         }
  3056.         ++options;
  3057.     }
  3058.     if (l[1] == '-')
  3059.         n = -n;
  3060.     switch (*l)
  3061.     {
  3062.         case '>': ind_level = n; break;
  3063.         case 'e': ind_open_imag = n; break;
  3064.         case 'n': ind_no_brace = n; break;
  3065.         case 'f': ind_first_open = n; break;
  3066.         case '{': ind_open_extra = n; break;
  3067.         case '}': ind_close_extra = n; break;
  3068.         case '^': ind_open_left_imag = n; break;
  3069.         case ':': ind_case = n; break;
  3070.         case '=': ind_case_code = n; break;
  3071.         case 'p': ind_param = n; break;
  3072.         case 't': ind_func_type = n; break;
  3073.         case 'c': ind_in_comment = n; break;
  3074.         case '+': ind_continuation = n; break;
  3075.         case '(': ind_unclosed = n; break;
  3076.         case 'u': ind_unclosed2 = n; break;
  3077.         case ')': ind_maxparen = n; break;
  3078.         case '*': ind_maxcomment = n; break;
  3079.         case 'g': ind_scopedecl = n; break;
  3080.         case 'h': ind_scopedecl_code = n; break;
  3081.     }
  3082.     }
  3083.  
  3084.     /* remember where the cursor was when we started */
  3085.  
  3086.     cur_curpos = curwin->w_cursor;
  3087.  
  3088.     /* get the current contents of the line.
  3089.      * This is required, because onle the most recent line obtained with
  3090.      * ml_get is valid! */
  3091.  
  3092.     linecopy = vim_strsave(ml_get(cur_curpos.lnum));
  3093.     if (linecopy == NULL)
  3094.     return 0;
  3095.  
  3096.     /*
  3097.      * In insert mode and the cursor is on a ')' trunctate the line at the
  3098.      * cursor position.  We don't want to line up with the matching '(' when
  3099.      * inserting new stuff.
  3100.      */
  3101.     if ((State & INSERT) && linecopy[curwin->w_cursor.col] == ')')
  3102.     linecopy[curwin->w_cursor.col] = NUL;
  3103.  
  3104.     theline = skipwhite(linecopy);
  3105.  
  3106.     /* move the cursor to the start of the line */
  3107.  
  3108.     curwin->w_cursor.col = 0;
  3109.  
  3110.     /*
  3111.      * #defines and so on always go at the left when included in 'cinkeys'.
  3112.      */
  3113.     if (*theline == '#' && (*linecopy == '#' || in_cinkeys('#', ' ', TRUE)))
  3114.     {
  3115.     amount = 0;
  3116.     }
  3117.  
  3118.     /*
  3119.      * Is it a non-case label?    Then that goes at the left margin too.
  3120.      */
  3121.     else if (cin_islabel(ind_maxcomment))        /* XXX */
  3122.     {
  3123.     amount = 0;
  3124.     }
  3125.  
  3126.     /*
  3127.      * If we're inside a comment and not looking at the start of the
  3128.      * comment...
  3129.      */
  3130.     else if (!cin_iscomment(theline) &&
  3131.           (trypos = find_start_comment(ind_maxcomment)) != NULL) /* XXX */
  3132.     {
  3133.  
  3134.     /* find how indented the line beginning the comment is */
  3135.     getvcol(curwin, trypos, &col, NULL, NULL);
  3136.     amount = col;
  3137.  
  3138.     /* if our line starts with an asterisk, line up with the
  3139.      * asterisk in the comment opener; otherwise, line up
  3140.      * with the first character of the comment text.
  3141.      */
  3142.     if (theline[0] == '*')
  3143.     {
  3144.         amount += 1;
  3145.     }
  3146.     else
  3147.     {
  3148.         /*
  3149.          * If we are more than one line away from the comment opener, take
  3150.          * the indent of the previous non-empty line.
  3151.          * If we are just below the comment opener and there are any
  3152.          * white characters after it line up with the text after it.
  3153.          * up with them; otherwise, just use a single space.
  3154.          */
  3155.         amount = -1;
  3156.         for (lnum = cur_curpos.lnum - 1; lnum > trypos->lnum; --lnum)
  3157.         {
  3158.         if (linewhite(lnum))            /* skip blank lines */
  3159.             continue;
  3160.         amount = get_indent_lnum(lnum);        /* XXX */
  3161.         break;
  3162.         }
  3163.         if (amount == -1)                /* use the comment opener */
  3164.         {
  3165.         start = ml_get(trypos->lnum);
  3166.         look = start + trypos->col + 2;        /* skip / and * */
  3167.         if (*look)                /* if something after it */
  3168.             trypos->col = skipwhite(look) - start;
  3169.         getvcol(curwin, trypos, &col, NULL, NULL);
  3170.         amount = col;
  3171.         if (!*look)
  3172.             amount += ind_in_comment;
  3173.         }
  3174.     }
  3175.     }
  3176.  
  3177.     /*
  3178.      * Are we inside parentheses?
  3179.      */                            /* XXX */
  3180.     else if ((trypos = find_match_paren(ind_maxparen, ind_maxcomment)) != NULL)
  3181.     {
  3182.     /*
  3183.      * If the matching paren is more than one line away, use the indent of
  3184.      * a previous non-empty line that matches the same paren.
  3185.      */
  3186.     amount = -1;
  3187.     our_paren_pos = *trypos;
  3188.     if (theline[0] != ')')
  3189.     {
  3190.         for (lnum = cur_curpos.lnum - 1; lnum > our_paren_pos.lnum; --lnum)
  3191.         {
  3192.         l = skipwhite(ml_get(lnum));
  3193.         if (commentorempty(l))        /* skip comment lines */
  3194.             continue;
  3195.         if (cin_ispreproc(l))        /* ignore #defines, #if, etc. */
  3196.             continue;
  3197.         curwin->w_cursor.lnum = lnum;
  3198.  
  3199.         /* Skip a comment. XXX */
  3200.         if ((trypos = find_start_comment(ind_maxcomment)) != NULL)
  3201.         {
  3202.             lnum = trypos->lnum + 1;
  3203.             continue;
  3204.         }
  3205.  
  3206.         /* XXX */
  3207.         if ((trypos = find_match_paren(ind_maxparen,
  3208.                            ind_maxcomment)) != NULL &&
  3209.                      trypos->lnum == our_paren_pos.lnum &&
  3210.                          trypos->col == our_paren_pos.col)
  3211.         {
  3212.             amount = get_indent_lnum(lnum);    /* XXX */
  3213.             break;
  3214.         }
  3215.         }
  3216.     }
  3217.  
  3218.     /*
  3219.      * Line up with line where the matching paren is. XXX
  3220.      * If the line starts with a '(' or the indent for unclosed
  3221.      * parentheses is zero, line up with the unclosed parentheses.
  3222.      */
  3223.     if (amount == -1)
  3224.     {
  3225.         amount = skip_label(our_paren_pos.lnum, &look, ind_maxcomment);
  3226.         if (theline[0] == ')' || ind_unclosed == 0 ||
  3227.                               *skipwhite(look) == '(')
  3228.         {
  3229.         /*
  3230.          * If we're looking at a close paren, line up right there;
  3231.          * otherwise, line up with the next non-white character.
  3232.          */
  3233.         if (theline[0] != ')')
  3234.         {
  3235.             col = our_paren_pos.col + 1;
  3236.             look = ml_get(our_paren_pos.lnum);
  3237.             while (vim_iswhite(look[col]))
  3238.             col++;
  3239.             if (look[col] != NUL)    /* In case of trailing space */
  3240.             our_paren_pos.col = col;
  3241.             else
  3242.             our_paren_pos.col++;
  3243.         }
  3244.  
  3245.         /*
  3246.          * Find how indented the paren is, or the character after it if
  3247.          * we did the above "if".
  3248.          */
  3249.         getvcol(curwin, &our_paren_pos, &col, NULL, NULL);
  3250.         amount = col;
  3251.         }
  3252.         else
  3253.         {
  3254.         /* add ind_unclosed2 for each '(' before our matching one */
  3255.         col = our_paren_pos.col;
  3256.         while (our_paren_pos.col > 0)
  3257.         {
  3258.             --our_paren_pos.col;
  3259.             switch (*ml_get_pos(&our_paren_pos))
  3260.             {
  3261.             case '(': amount += ind_unclosed2;
  3262.                   col = our_paren_pos.col;
  3263.                   break;
  3264.             case ')': amount -= ind_unclosed2;
  3265.                   col = MAXCOL;
  3266.                   break;
  3267.             }
  3268.         }
  3269.  
  3270.         /* Use ind_unclosed once, when the first '(' is not inside
  3271.          * braces */
  3272.         if (col == MAXCOL)
  3273.             amount += ind_unclosed;
  3274.         else
  3275.         {
  3276.             curwin->w_cursor.lnum = our_paren_pos.lnum;
  3277.             curwin->w_cursor.col = col;
  3278.             if ((trypos = find_match_paren(ind_maxparen,
  3279.                              ind_maxcomment)) != NULL)
  3280.             amount += ind_unclosed2;
  3281.             else
  3282.             amount += ind_unclosed;
  3283.         }
  3284.         }
  3285.     }
  3286.     }
  3287.  
  3288.     /*
  3289.      * Are we at least inside braces, then?
  3290.      */
  3291.     else if ((trypos = find_start_brace(ind_maxcomment)) != NULL) /* XXX */
  3292.     {
  3293.     ourscope = trypos->lnum;
  3294.     start = ml_get(ourscope);
  3295.  
  3296.     /*
  3297.      * Now figure out how indented the line is in general.
  3298.      * If the brace was at the start of the line, we use that;
  3299.      * otherwise, check out the indentation of the line as
  3300.      * a whole and then add the "imaginary indent" to that.
  3301.      */
  3302.     look = skipwhite(start);
  3303.     if (*look == '{')
  3304.     {
  3305.         getvcol(curwin, trypos, &col, NULL, NULL);
  3306.         amount = col;
  3307.         if (*start == '{')
  3308.         start_brace = BRACE_IN_COL0;
  3309.         else
  3310.         start_brace = BRACE_AT_START;
  3311.     }
  3312.     else
  3313.     {
  3314.         /*
  3315.          * that opening brace might have been on a continuation
  3316.          * line.  if so, find the start of the line.
  3317.          */
  3318.         curwin->w_cursor.lnum = ourscope;
  3319.  
  3320.         /*
  3321.          * position the cursor over the rightmost paren, so that
  3322.          * matching it will take us back to the start of the line.
  3323.          */
  3324.         lnum = ourscope;
  3325.         if (find_last_paren(start) &&
  3326.             (trypos = find_match_paren(ind_maxparen,
  3327.                              ind_maxcomment)) != NULL)
  3328.         lnum = trypos->lnum;
  3329.  
  3330.         /*
  3331.          * It could have been something like
  3332.          *       case 1: if (asdf &&
  3333.          *            ldfd) {
  3334.          *            }
  3335.          */
  3336.         amount = skip_label(lnum, &l, ind_maxcomment);
  3337.  
  3338.         start_brace = BRACE_AT_END;
  3339.     }
  3340.  
  3341.     /*
  3342.      * if we're looking at a closing brace, that's where
  3343.      * we want to be.  otherwise, add the amount of room
  3344.      * that an indent is supposed to be.
  3345.      */
  3346.     if (theline[0] == '}')
  3347.     {
  3348.         /*
  3349.          * they may want closing braces to line up with something
  3350.          * other than the open brace.  indulge them, if so.
  3351.          */
  3352.         amount += ind_close_extra;
  3353.     }
  3354.     else
  3355.     {
  3356.         /*
  3357.          * If we're looking at an "else", try to find an "if"
  3358.          * to match it with.
  3359.          * If we're looking at a "while", try to find a "do"
  3360.          * to match it with.
  3361.          */
  3362.         lookfor = 0;
  3363.         if (cin_iselse(theline))
  3364.         lookfor = LOOKFOR_IF;
  3365.         else if (cin_iswhileofdo(theline, cur_curpos.lnum, ind_maxparen))
  3366.                                     /* XXX */
  3367.         lookfor = LOOKFOR_DO;
  3368.         if (lookfor)
  3369.         {
  3370.         curwin->w_cursor.lnum = cur_curpos.lnum;
  3371.         if (find_match(lookfor, ourscope, ind_maxparen,
  3372.                             ind_maxcomment) == OK)
  3373.         {
  3374.             amount = get_indent();    /* XXX */
  3375.             goto theend;
  3376.         }
  3377.         }
  3378.  
  3379.         /*
  3380.          * We get here if we are not on an "while-of-do" or "else" (or
  3381.          * failed to find a matching "if").
  3382.          * Search backwards for something to line up with.
  3383.          * First set amount for when we don't find anything.
  3384.          */
  3385.  
  3386.         /*
  3387.          * if the '{' is  _really_ at the left margin, use the imaginary
  3388.          * location of a left-margin brace.  Otherwise, correct the
  3389.          * location for ind_open_extra.
  3390.          */
  3391.  
  3392.         if (start_brace == BRACE_IN_COL0)        /* '{' is in column 0 */
  3393.         {
  3394.         amount = ind_open_left_imag;
  3395.         }
  3396.         else
  3397.         {
  3398.         if (start_brace == BRACE_AT_END)    /* '{' is at end of line */
  3399.             amount += ind_open_imag;
  3400.         else
  3401.         {
  3402.             amount -= ind_open_extra;
  3403.             if (amount < 0)
  3404.             amount = 0;
  3405.         }
  3406.         }
  3407.  
  3408.         if (cin_iscase(theline))    /* it's a switch() label */
  3409.         {
  3410.         lookfor = LOOKFOR_CASE;    /* find a previous switch() label */
  3411.         amount += ind_case;
  3412.         }
  3413.         else if (cin_isscopedecl(theline))    /* private:, ... */
  3414.         {
  3415.         lookfor = LOOKFOR_SCOPEDECL;    /* class decl is this block */
  3416.         amount += ind_scopedecl;
  3417.         }
  3418.         else
  3419.         {
  3420.         lookfor = LOOKFOR_ANY;
  3421.         amount += ind_level;    /* ind_level from start of block */
  3422.         }
  3423.         scope_amount = amount;
  3424.         whilelevel = 0;
  3425.  
  3426.         /*
  3427.          * Search backwards.  If we find something we recognize, line up
  3428.          * with that.
  3429.          *
  3430.          * if we're looking at an open brace, indent
  3431.          * the usual amount relative to the conditional
  3432.          * that opens the block.
  3433.          */
  3434.         curwin->w_cursor = cur_curpos;
  3435.         for (;;)
  3436.         {
  3437.         curwin->w_cursor.lnum--;
  3438.         curwin->w_cursor.col = 0;
  3439.  
  3440.         /*
  3441.          * If we went all the way back to the start of our scope, line
  3442.          * up with it.
  3443.          */
  3444.         if (curwin->w_cursor.lnum <= ourscope)
  3445.         {
  3446.             if (lookfor == LOOKFOR_UNTERM)
  3447.             amount += ind_continuation;
  3448.             else if (lookfor != LOOKFOR_TERM)
  3449.             amount = scope_amount;
  3450.             break;
  3451.         }
  3452.  
  3453.         /*
  3454.          * If we're in a comment now, skip to the start of the comment.
  3455.          */                        /* XXX */
  3456.         if ((trypos = find_start_comment(ind_maxcomment)) != NULL)
  3457.         {
  3458.             curwin->w_cursor.lnum = trypos->lnum + 1;
  3459.             continue;
  3460.         }
  3461.  
  3462.         l = ml_get_curline();
  3463.  
  3464.         /*
  3465.          * If this is a switch() label, may line up relative to that.
  3466.          * if this is a C++ scope declaration, do the same.
  3467.          */
  3468.         iscase = cin_iscase(l);
  3469.         if (iscase || cin_isscopedecl(l))
  3470.         {
  3471.             /*
  3472.              *    case xx:
  3473.              *        c = 99 +        <- this indent plus continuation
  3474.              *->       here;
  3475.              */
  3476.             if (lookfor == LOOKFOR_UNTERM)
  3477.             {
  3478.             amount += ind_continuation;
  3479.             break;
  3480.             }
  3481.  
  3482.             /*
  3483.              *    case xx:    <- line up with this case
  3484.              *        x = 333;
  3485.              *    case yy:
  3486.              */
  3487.             if (       (iscase && lookfor == LOOKFOR_CASE)
  3488.                 || (!iscase && lookfor == LOOKFOR_SCOPEDECL))
  3489.             {
  3490.             /*
  3491.              * Check that this case label is not for another
  3492.              * switch()
  3493.              */                    /* XXX */
  3494.             if ((trypos = find_start_brace(ind_maxcomment)) ==
  3495.                          NULL || trypos->lnum == ourscope)
  3496.             {
  3497.                 amount = get_indent();    /* XXX */
  3498.                 break;
  3499.             }
  3500.             continue;
  3501.             }
  3502.  
  3503.             n = get_indent_nolabel(curwin->w_cursor.lnum);  /* XXX */
  3504.  
  3505.             /*
  3506.              *     case xx: if (cond)        <- line up with this if
  3507.              *              y = y + 1;
  3508.              * ->      s = 99;
  3509.              *
  3510.              *     case xx:
  3511.              *         if (cond)        <- line up with this line
  3512.              *         y = y + 1;
  3513.              * ->    s = 99;
  3514.              */
  3515.             if (lookfor == LOOKFOR_TERM)
  3516.             {
  3517.             if (n)
  3518.                 amount = n;
  3519.             break;
  3520.             }
  3521.  
  3522.             /*
  3523.              *     case xx: x = x + 1;        <- line up with this x
  3524.              * ->      y = y + 1;
  3525.              *
  3526.              *     case xx: if (cond)        <- line up with this if
  3527.              * ->           y = y + 1;
  3528.              */
  3529.             if (n)
  3530.             {
  3531.             amount = n;
  3532.             l = after_label(ml_get_curline());
  3533.             if (l != NULL && cin_is_cinword(l))
  3534.                 amount += ind_level + ind_no_brace;
  3535.             break;
  3536.             }
  3537.  
  3538.             /*
  3539.              * Try to get the indent of a statement before the switch
  3540.              * label.  If nothing is found, line up relative to the
  3541.              * switch label.
  3542.              *        break;        <- may line up with this line
  3543.              *     case xx:
  3544.              * ->   y = 1;
  3545.              */
  3546.             scope_amount = get_indent() + (iscase    /* XXX */
  3547.                     ? ind_case_code : ind_scopedecl_code);
  3548.             lookfor = LOOKFOR_ANY;
  3549.             continue;
  3550.         }
  3551.  
  3552.         /*
  3553.          * Looking for a switch() label or C++ scope declaration,
  3554.          * ignore other lines.
  3555.          */
  3556.         if (lookfor == LOOKFOR_CASE || lookfor == LOOKFOR_SCOPEDECL)
  3557.             continue;
  3558.  
  3559.         /*
  3560.          * Ignore jump labels with nothing after them.
  3561.          */
  3562.         if (cin_islabel(ind_maxcomment))
  3563.         {
  3564.             l = after_label(ml_get_curline());
  3565.             if (l == NULL || commentorempty(l))
  3566.             continue;
  3567.         }
  3568.  
  3569.         /*
  3570.          * Ignore #defines, #if, etc.
  3571.          * Ignore comment and empty lines.
  3572.          * (need to get the line again, cin_islabel() may have
  3573.          * unlocked it)
  3574.          */
  3575.         l = ml_get_curline();
  3576.         if (cin_ispreproc(l) || commentorempty(l))
  3577.             continue;
  3578.  
  3579.         /*
  3580.          * What happens next depends on the line being terminated.
  3581.          */
  3582.         if (!cin_isterminated(l, FALSE))
  3583.         {
  3584.             /*
  3585.              * if we're in the middle of a paren thing,
  3586.              * go back to the line that starts it so
  3587.              * we can get the right prevailing indent
  3588.              *       if ( foo &&
  3589.              *            bar )
  3590.              */
  3591.             /*
  3592.              * position the cursor over the rightmost paren, so that
  3593.              * matching it will take us back to the start of the line.
  3594.              */
  3595.             (void)find_last_paren(l);
  3596.             if ((trypos = find_match_paren(ind_maxparen,
  3597.                              ind_maxcomment)) != NULL)
  3598.             {
  3599.             /*
  3600.              * Check if we are on a case label now.  This is
  3601.              * handled above.
  3602.              *     case xx:  if ( asdf &&
  3603.              *            asdf)
  3604.              */
  3605.             curwin->w_cursor.lnum = trypos->lnum;
  3606.             l = ml_get_curline();
  3607.             if (cin_iscase(l) || cin_isscopedecl(l))
  3608.             {
  3609.                 ++curwin->w_cursor.lnum;
  3610.                 continue;
  3611.             }
  3612.             }
  3613.  
  3614.             /*
  3615.              * Get indent and pointer to text for current line,
  3616.              * ignoring any jump label.        XXX
  3617.              */
  3618.             cur_amount = skip_label(curwin->w_cursor.lnum,
  3619.                               &l, ind_maxcomment);
  3620.  
  3621.             /*
  3622.              * If this is just above the line we are indenting, and it
  3623.              * starts with a '{', line it up with this line.
  3624.              *        while (not)
  3625.              * ->    {
  3626.              *        }
  3627.              */
  3628.             if (lookfor != LOOKFOR_TERM && theline[0] == '{')
  3629.             {
  3630.             amount = cur_amount + ind_open_extra;
  3631.             break;
  3632.             }
  3633.  
  3634.             /*
  3635.              * Check if we are after an "if", "while", etc.
  3636.              * Also allow "} else".
  3637.              */
  3638.             if (cin_is_cinword(l) || cin_iselse(l))
  3639.             {
  3640.             /*
  3641.              * Found an unterminated line after an if (), line up
  3642.              * with the last one.
  3643.              *   if (cond)
  3644.              *        100 +
  3645.              * ->        here;
  3646.              */
  3647.             if (lookfor == LOOKFOR_UNTERM)
  3648.             {
  3649.                 amount += ind_continuation;
  3650.                 break;
  3651.             }
  3652.  
  3653.             /*
  3654.              * If this is just above the line we are indenting, we
  3655.              * are finished.
  3656.              *        while (not)
  3657.              * ->        here;
  3658.              * Otherwise this indent can be used when the line
  3659.              * before this is terminated.
  3660.              *    yyy;
  3661.              *    if (stat)
  3662.              *        while (not)
  3663.              *        xxx;
  3664.              * ->    here;
  3665.              */
  3666.             amount = cur_amount;
  3667.             if (lookfor != LOOKFOR_TERM)
  3668.             {
  3669.                 amount += ind_level + ind_no_brace;
  3670.                 break;
  3671.             }
  3672.  
  3673.             /*
  3674.              * Special trick: when expecting the while () after a
  3675.              * do, line up with the while()
  3676.              *     do
  3677.              *        x = 1;
  3678.              * ->  here
  3679.              */
  3680.             l = skipwhite(ml_get_curline());
  3681.             if (cin_isdo(l))
  3682.             {
  3683.                 if (whilelevel == 0)
  3684.                 break;
  3685.                 --whilelevel;
  3686.             }
  3687.  
  3688.             /*
  3689.              * When searching for a terminated line, don't use the
  3690.              * one between the "if" and the "else".
  3691.              * Need to use the scope of this "else".  XXX
  3692.              */
  3693.             if (cin_iselse(l) &&
  3694.                 ((trypos = find_start_brace(ind_maxcomment))
  3695.                                     == NULL ||
  3696.                 find_match(LOOKFOR_IF, trypos->lnum,
  3697.                     ind_maxparen, ind_maxcomment) == FAIL))
  3698.                 break;
  3699.             }
  3700.  
  3701.             /*
  3702.              * If we're below an unterminated line that is not an
  3703.              * "if" or something, we may line up with this line or
  3704.              * add someting for a continuation line, depending on
  3705.              * the line before this one.
  3706.              */
  3707.             else
  3708.             {
  3709.             /*
  3710.              * Found two unterminated lines on a row, line up with
  3711.              * the last one.
  3712.              *   c = 99 +
  3713.              *        100 +
  3714.              * ->        here;
  3715.              */
  3716.             if (lookfor == LOOKFOR_UNTERM)
  3717.                 break;
  3718.  
  3719.             /*
  3720.              * Found first unterminated line on a row, may line up
  3721.              * with this line, remember its indent
  3722.              *        100 +
  3723.              * ->        here;
  3724.              */
  3725.             amount = cur_amount;
  3726.             if (lookfor != LOOKFOR_TERM)
  3727.                 lookfor = LOOKFOR_UNTERM;
  3728.             }
  3729.         }
  3730.  
  3731.         /*
  3732.          * Check if we are after a while (cond);
  3733.          * If so: Ignore until the matching "do".
  3734.          */
  3735.                             /* XXX */
  3736.         else if (cin_iswhileofdo(l,
  3737.                      curwin->w_cursor.lnum, ind_maxparen))
  3738.         {
  3739.             /*
  3740.              * Found an unterminated line after a while ();, line up
  3741.              * with the last one.
  3742.              *        while (cond);
  3743.              *        100 +        <- line up with this one
  3744.              * ->        here;
  3745.              */
  3746.             if (lookfor == LOOKFOR_UNTERM)
  3747.             {
  3748.             amount += ind_continuation;
  3749.             break;
  3750.             }
  3751.  
  3752.             if (whilelevel == 0)
  3753.             {
  3754.             lookfor = LOOKFOR_TERM;
  3755.             amount = get_indent();        /* XXX */
  3756.             if (theline[0] == '{')
  3757.                 amount += ind_open_extra;
  3758.             }
  3759.             ++whilelevel;
  3760.         }
  3761.  
  3762.         /*
  3763.          * We are after a "normal" statement.
  3764.          * If we had another statement we can stop now and use the
  3765.          * indent of that other statement.
  3766.          * Otherwise the indent of the current statement may be used,
  3767.          * search backwards for the next "normal" statement.
  3768.          */
  3769.         else
  3770.         {
  3771.             /*
  3772.              * Handle "do {" line.
  3773.              */
  3774.             if (whilelevel > 0)
  3775.             {
  3776.             l = skipwhite(ml_get_curline());
  3777.             if (cin_isdo(l))
  3778.             {
  3779.                 amount = get_indent();    /* XXX */
  3780.                 --whilelevel;
  3781.                 continue;
  3782.             }
  3783.             }
  3784.  
  3785.             /*
  3786.              * Found a terminated line above an unterminated line. Add
  3787.              * the amount for a continuation line.
  3788.              *     x = 1;
  3789.              *     y = foo +
  3790.              * ->    here;
  3791.              */
  3792.             if (lookfor == LOOKFOR_UNTERM)
  3793.             {
  3794.             amount += ind_continuation;
  3795.             break;
  3796.             }
  3797.  
  3798.             /*
  3799.              * Found a terminated line above a terminated line or "if"
  3800.              * etc. line. Use the amount of the line below us.
  3801.              *     x = 1;                x = 1;
  3802.              *     if (asdf)            y = 2;
  3803.              *         while (asdf)      ->here;
  3804.              *        here;
  3805.              * ->foo;
  3806.              */
  3807.             if (lookfor == LOOKFOR_TERM)
  3808.             {
  3809.             if (whilelevel == 0)
  3810.                 break;
  3811.             }
  3812.  
  3813.             /*
  3814.              * First line above the one we're indenting is terminated.
  3815.              * To know what needs to be done look further backward for
  3816.              * a terminated line.
  3817.              */
  3818.             else
  3819.             {
  3820.             /*
  3821.              * position the cursor over the rightmost paren, so
  3822.              * that matching it will take us back to the start of
  3823.              * the line.  Helps for:
  3824.              *     func(asdr,
  3825.              *          asdfasdf);
  3826.              *     here;
  3827.              */
  3828. term_again:
  3829.             l = ml_get_curline();
  3830.             if (find_last_paren(l) &&
  3831.                 (trypos = find_match_paren(ind_maxparen,
  3832.                              ind_maxcomment)) != NULL)
  3833.             {
  3834.                 /*
  3835.                  * Check if we are on a case label now.  This is
  3836.                  * handled above.
  3837.                  *       case xx:  if ( asdf &&
  3838.                  *                asdf)
  3839.                  */
  3840.                 curwin->w_cursor.lnum = trypos->lnum;
  3841.                 l = ml_get_curline();
  3842.                 if (cin_iscase(l) || cin_isscopedecl(l))
  3843.                 {
  3844.                 ++curwin->w_cursor.lnum;
  3845.                 continue;
  3846.                 }
  3847.             }
  3848.  
  3849.             /*
  3850.              * Get indent and pointer to text for current line,
  3851.              * ignoring any jump label.
  3852.              */
  3853.             amount = skip_label(curwin->w_cursor.lnum,
  3854.                               &l, ind_maxcomment);
  3855.  
  3856.             if (theline[0] == '{')
  3857.                 amount += ind_open_extra;
  3858.             lookfor = LOOKFOR_TERM;
  3859.  
  3860.             /*
  3861.              * If we're at the end of a block, skip to the start of
  3862.              * that block.
  3863.              */
  3864.             curwin->w_cursor.col = 0;
  3865.             if (*skipwhite(l) == '}' &&
  3866.                    (trypos = find_start_brace(ind_maxcomment))
  3867.                                 != NULL) /* XXX */
  3868.             {
  3869.                 curwin->w_cursor.lnum = trypos->lnum;
  3870.                 /* if not "else {" check for terminated again */
  3871.                 if (!cin_iselse(skipwhite(ml_get_curline())))
  3872.                 goto term_again;
  3873.                 ++curwin->w_cursor.lnum;
  3874.             }
  3875.             }
  3876.         }
  3877.         }
  3878.     }
  3879.     }
  3880.  
  3881.     /*
  3882.      * ok -- we're not inside any sort of structure at all!
  3883.      *
  3884.      * this means we're at the top level, and everything should
  3885.      * basically just match where the previous line is, except
  3886.      * for the lines immediately following a function declaration,
  3887.      * which are K&R-style parameters and need to be indented.
  3888.      */
  3889.     else
  3890.     {
  3891.     /*
  3892.      * if our line starts with an open brace, forget about any
  3893.      * prevailing indent and make sure it looks like the start
  3894.      * of a function
  3895.      */
  3896.  
  3897.     if (theline[0] == '{')
  3898.     {
  3899.         amount = ind_first_open;
  3900.     }
  3901.  
  3902.     /*
  3903.      * If the NEXT line is a function declaration, the current
  3904.      * line needs to be indented as a function type spec.
  3905.      * Don't do this if the current line looks like a comment.
  3906.      */
  3907.     else if (cur_curpos.lnum < curbuf->b_ml.ml_line_count
  3908.         && !commentorempty(theline)
  3909.         && cin_isfuncdecl(ml_get(cur_curpos.lnum + 1)))
  3910.     {
  3911.         amount = ind_func_type;
  3912.     }
  3913.     else
  3914.     {
  3915.         amount = 0;
  3916.         curwin->w_cursor = cur_curpos;
  3917.  
  3918.         /* search backwards until we find something we recognize */
  3919.  
  3920.         while (curwin->w_cursor.lnum > 1)
  3921.         {
  3922.         curwin->w_cursor.lnum--;
  3923.         curwin->w_cursor.col = 0;
  3924.  
  3925.         l = ml_get_curline();
  3926.  
  3927.         /*
  3928.          * If we're in a comment now, skip to the start of the comment.
  3929.          */                        /* XXX */
  3930.         if ((trypos = find_start_comment(ind_maxcomment)) != NULL)
  3931.         {
  3932.             curwin->w_cursor.lnum = trypos->lnum + 1;
  3933.             continue;
  3934.         }
  3935.  
  3936.         /*
  3937.          * If the line looks like a function declaration, and we're
  3938.          * not in a comment, put it the left margin.
  3939.          */
  3940.         if (cin_isfuncdecl(theline))
  3941.             break;
  3942.  
  3943.         /*
  3944.          * Skip preprocessor directives and blank lines.
  3945.          */
  3946.         if (cin_ispreproc(l))
  3947.             continue;
  3948.  
  3949.         if (commentorempty(l))
  3950.             continue;
  3951.  
  3952.         /*
  3953.          * If the PREVIOUS line is a function declaration, the current
  3954.          * line (and the ones that follow) needs to be indented as
  3955.          * parameters.
  3956.          */
  3957.         if (cin_isfuncdecl(l))
  3958.         {
  3959.             amount = ind_param;
  3960.             break;
  3961.         }
  3962.  
  3963.         /*
  3964.          * Doesn't look like anything interesting -- so just
  3965.          * use the indent of this line.
  3966.          *
  3967.          * Position the cursor over the rightmost paren, so that
  3968.          * matching it will take us back to the start of the line.
  3969.          */
  3970.         find_last_paren(l);
  3971.  
  3972.         if ((trypos = find_match_paren(ind_maxparen,
  3973.                              ind_maxcomment)) != NULL)
  3974.             curwin->w_cursor.lnum = trypos->lnum;
  3975.         amount = get_indent();        /* XXX */
  3976.         break;
  3977.         }
  3978.     }
  3979.     }
  3980.  
  3981. theend:
  3982.     /* put the cursor back where it belongs */
  3983.     curwin->w_cursor = cur_curpos;
  3984.  
  3985.     vim_free(linecopy);
  3986.  
  3987.     if (amount < 0)
  3988.     return 0;
  3989.     return amount;
  3990. }
  3991.  
  3992.     static int
  3993. find_match(lookfor, ourscope, ind_maxparen, ind_maxcomment)
  3994.     int        lookfor;
  3995.     linenr_t    ourscope;
  3996.     int        ind_maxparen;
  3997.     int        ind_maxcomment;
  3998. {
  3999.     char_u    *look;
  4000.     FPOS    *theirscope;
  4001.     char_u    *mightbeif;
  4002.     int        elselevel;
  4003.     int        whilelevel;
  4004.  
  4005.     if (lookfor == LOOKFOR_IF)
  4006.     {
  4007.     elselevel = 1;
  4008.     whilelevel = 0;
  4009.     }
  4010.     else
  4011.     {
  4012.     elselevel = 0;
  4013.     whilelevel = 1;
  4014.     }
  4015.  
  4016.     curwin->w_cursor.col = 0;
  4017.  
  4018.     while (curwin->w_cursor.lnum > ourscope + 1)
  4019.     {
  4020.     curwin->w_cursor.lnum--;
  4021.     curwin->w_cursor.col = 0;
  4022.  
  4023.     look = skipwhite(ml_get_curline());
  4024.     if (cin_iselse(look)
  4025.         || cin_isif(look)
  4026.         || cin_isdo(look)                /* XXX */
  4027.         || cin_iswhileofdo(look, curwin->w_cursor.lnum, ind_maxparen))
  4028.     {
  4029.         /*
  4030.          * if we've gone outside the braces entirely,
  4031.          * we must be out of scope...
  4032.          */
  4033.         theirscope = find_start_brace(ind_maxcomment);  /* XXX */
  4034.         if (theirscope == NULL)
  4035.         break;
  4036.  
  4037.         /*
  4038.          * and if the brace enclosing this is further
  4039.          * back than the one enclosing the else, we're
  4040.          * out of luck too.
  4041.          */
  4042.         if (theirscope->lnum < ourscope)
  4043.         break;
  4044.  
  4045.         /*
  4046.          * and if they're enclosed in a *deeper* brace,
  4047.          * then we can ignore it because it's in a
  4048.          * different scope...
  4049.          */
  4050.         if (theirscope->lnum > ourscope)
  4051.         continue;
  4052.  
  4053.         /*
  4054.          * if it was an "else" (that's not an "else if")
  4055.          * then we need to go back to another if, so
  4056.          * increment elselevel
  4057.          */
  4058.         look = skipwhite(ml_get_curline());
  4059.         if (cin_iselse(look))
  4060.         {
  4061.         mightbeif = skipwhite(look + 4);
  4062.         if (!cin_isif(mightbeif))
  4063.             ++elselevel;
  4064.         continue;
  4065.         }
  4066.  
  4067.         /*
  4068.          * if it was a "while" then we need to go back to
  4069.          * another "do", so increment whilelevel.  XXX
  4070.          */
  4071.         if (cin_iswhileofdo(look, curwin->w_cursor.lnum, ind_maxparen))
  4072.         {
  4073.         ++whilelevel;
  4074.         continue;
  4075.         }
  4076.  
  4077.         /* If it's an "if" decrement elselevel */
  4078.         look = skipwhite(ml_get_curline());
  4079.         if (cin_isif(look))
  4080.         {
  4081.         elselevel--;
  4082.         /*
  4083.          * When looking for an "if" ignore "while"s that
  4084.          * get in the way.
  4085.          */
  4086.         if (elselevel == 0 && lookfor == LOOKFOR_IF)
  4087.             whilelevel = 0;
  4088.         }
  4089.  
  4090.         /* If it's a "do" decrement whilelevel */
  4091.         if (cin_isdo(look))
  4092.         whilelevel--;
  4093.  
  4094.         /*
  4095.          * if we've used up all the elses, then
  4096.          * this must be the if that we want!
  4097.          * match the indent level of that if.
  4098.          */
  4099.         if (elselevel <= 0 && whilelevel <= 0)
  4100.         {
  4101.         return OK;
  4102.         }
  4103.     }
  4104.     }
  4105.     return FAIL;
  4106. }
  4107.  
  4108. #endif /* CINDENT */
  4109.  
  4110. #ifdef LISPINDENT
  4111.     int
  4112. get_lisp_indent()
  4113. {
  4114.     FPOS    *pos, realpos;
  4115.     int        amount;
  4116.     char_u    *that;
  4117.     colnr_t    col;
  4118.     colnr_t    maybe;
  4119.     colnr_t    firsttry;
  4120.     int        count = 0;
  4121.  
  4122.  
  4123.     realpos = curwin->w_cursor;
  4124.     curwin->w_cursor.col = 0;
  4125.  
  4126.     if ((pos = findmatch(NULL, '(')) != NULL)
  4127.     {
  4128.     /* Extra trick: Take the indent of the first previous non-white line
  4129.      * that is at the same () level. */
  4130.     amount = -1;
  4131.     while (--curwin->w_cursor.lnum >= pos->lnum)
  4132.     {
  4133.         if (linewhite(curwin->w_cursor.lnum))
  4134.         continue;
  4135.         for (that = ml_get_curline(); *that; ++that)
  4136.         {
  4137.         if (*that == '(')
  4138.             ++count;
  4139.         else if (*that == ')')
  4140.             --count;
  4141.         }
  4142.         if (count == 0)
  4143.         {
  4144.         amount = get_indent();
  4145.         break;
  4146.         }
  4147.     }
  4148.  
  4149.     /* get the indent from where the matching '(' is */
  4150.     if (amount == -1)
  4151.     {
  4152.         curwin->w_cursor.lnum = pos->lnum;
  4153.         curwin->w_cursor.col = pos->col;
  4154.         col = pos->col;
  4155.  
  4156.         that = ml_get_curline();
  4157.         maybe = get_indent();
  4158.  
  4159.         if (maybe == 0)
  4160.         amount = 2;
  4161.         else
  4162.         {
  4163.         amount = 0;
  4164.         while (*that && col)
  4165.         {
  4166.             amount += lbr_chartabsize(that, (colnr_t)amount);
  4167.             col--;
  4168.             that++;
  4169.         }
  4170.  
  4171.         that++;
  4172.         amount++;
  4173.         firsttry = amount;
  4174.  
  4175.         /*
  4176.          * Go to the start of the second word.
  4177.          * If there is no second word, go back to firsttry.
  4178.          * Also stop at a '('.
  4179.          */
  4180.  
  4181.         while (vim_iswhite(*that))
  4182.         {
  4183.             amount += lbr_chartabsize(that, (colnr_t)amount);
  4184.             that++;
  4185.         }
  4186.         while (*that && !vim_iswhite(*that) && *that != '(')
  4187.         {
  4188.             amount += lbr_chartabsize(that, (colnr_t)amount);
  4189.             that++;
  4190.         }
  4191.         while (vim_iswhite(*that))
  4192.         {
  4193.             amount += lbr_chartabsize(that, (colnr_t)amount);
  4194.             that++;
  4195.         }
  4196.         if (*that == NUL)
  4197.             amount = firsttry;
  4198.         }
  4199.     }
  4200.     }
  4201.     else    /* no matching '(' found, use zero indent */
  4202.     amount = 0;
  4203.  
  4204.     curwin->w_cursor = realpos;
  4205.  
  4206.     return amount;
  4207. }
  4208. #endif /* LISPINDENT */
  4209.  
  4210. /*
  4211.  * Preserve files and exit.
  4212.  * When called IObuff must contain a message.
  4213.  */
  4214.     void
  4215. preserve_exit()
  4216. {
  4217.     BUF        *buf;
  4218.  
  4219. #ifdef USE_GUI
  4220.     if (gui.in_use)
  4221.     {
  4222.     gui.dying = TRUE;
  4223.     out_trash();    /* trash any pending output */
  4224.     }
  4225.     else
  4226. #endif
  4227.     {
  4228.     windgoto((int)Rows - 1, 0);
  4229.  
  4230.     /*
  4231.      * Switch terminal mode back now, so these messages end up on the
  4232.      * "normal" screen (if there are two screens).
  4233.      */
  4234.     settmode(TMODE_COOK);
  4235. #ifdef WIN32
  4236.     if (can_end_termcap_mode(FALSE) == TRUE)
  4237. #endif
  4238.         stoptermcap();
  4239.     out_flush();
  4240.     }
  4241.  
  4242.     out_str(IObuff);
  4243.     screen_start();            /* don't know where cursor is now */
  4244.     out_flush();
  4245.  
  4246.     ml_close_notmod();            /* close all not-modified buffers */
  4247.  
  4248.     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  4249.     {
  4250.     if (buf->b_ml.ml_mfp != NULL && buf->b_ml.ml_mfp->mf_fname != NULL)
  4251.     {
  4252.         OUT_STR("Vim: preserving files...\n");
  4253.         screen_start();        /* don't know where cursor is now */
  4254.         out_flush();
  4255.         ml_sync_all(FALSE, FALSE);    /* preserve all swap files */
  4256.         break;
  4257.     }
  4258.     }
  4259.  
  4260.     ml_close_all(FALSE);        /* close all memfiles, without deleting */
  4261.  
  4262.     OUT_STR("Vim: Finished.\n");
  4263.  
  4264.     getout(1);
  4265. }
  4266.  
  4267. /*
  4268.  * return TRUE if "fname" exists.
  4269.  */
  4270.     int
  4271. vim_fexists(fname)
  4272.     char_u  *fname;
  4273. {
  4274.     struct stat st;
  4275.  
  4276.     if (stat((char *)fname, &st))
  4277.     return FALSE;
  4278.     return TRUE;
  4279. }
  4280.  
  4281. /*
  4282.  * Check for CTRL-C pressed, but only once in a while.
  4283.  * Should be used instead of ui_breakcheck() for functions that check for
  4284.  * each line in the file.  Calling ui_breakcheck() each time takes too much
  4285.  * time, because it can be a system call.
  4286.  */
  4287.  
  4288. #ifndef BREAKCHECK_SKIP
  4289. # ifdef USE_GUI            /* assume the GUI only runs on fast computers */
  4290. #  define BREAKCHECK_SKIP 200
  4291. # else
  4292. #  define BREAKCHECK_SKIP 32
  4293. # endif
  4294. #endif
  4295.  
  4296.     void
  4297. line_breakcheck()
  4298. {
  4299.     static int    count = 0;
  4300.  
  4301.     if (++count == BREAKCHECK_SKIP)
  4302.     {
  4303.     count = 0;
  4304.     ui_breakcheck();
  4305.     }
  4306. }
  4307.  
  4308. #ifndef NO_EXPANDPATH
  4309. /*
  4310.  * Generic wildcard expansion code.
  4311.  *
  4312.  * Return FAIL when no single file was found.  In this case "num_file" is not
  4313.  * set, and "file" may contain an error message.
  4314.  * Return OK when some files found.  "num_file" is set to the number of
  4315.  * matches, "file" to the array of matches.  Call FreeWild() later.
  4316.  */
  4317.     int
  4318. expand_wildcards(num_pat, pat, num_file, file, flags)
  4319.     int        num_pat;        /* number of input patterns */
  4320.     char_u  **pat;        /* array of input patterns */
  4321.     int        *num_file;        /* resulting number of files */
  4322.     char_u  ***file;        /* array of resulting files */
  4323.     int        flags;        /* EW_DIR, EW_FILE, EW_NOTFOUND */
  4324. {
  4325.     int            i;
  4326.     struct growarray    ga;
  4327.     char_u        *p;
  4328.     static int        recursive = FALSE;
  4329.  
  4330.     /*
  4331.      * expand_env() is called to expand things like "~user".  If this fails,
  4332.      * it calls ExpandOne(), which brings us back here.  In this case, always
  4333.      * call the machine specific expansion function, if possible.  Otherwise,
  4334.      * return FAIL.
  4335.      */
  4336.     if (recursive)
  4337. #ifdef SPECIAL_WILDCHAR
  4338.     return mch_expand_wildcards(num_pat, pat, num_file, file, flags);
  4339. #else
  4340.     return FAIL;
  4341. #endif
  4342.  
  4343. #ifdef SPECIAL_WILDCHAR
  4344.     /*
  4345.      * If there are any special wildcard characters which we cannot handle
  4346.      * here, call machine specific function for all the expansion.  This
  4347.      * avoids starting the shell for each argument separately.
  4348.      */
  4349.     for (i = 0; i < num_pat; i++)
  4350.     {
  4351.     if (vim_strpbrk(pat[i], (char_u *)SPECIAL_WILDCHAR) != NULL)
  4352.         return mch_expand_wildcards(num_pat, pat, num_file, file, flags);
  4353.     }
  4354. #endif
  4355.  
  4356.     recursive = TRUE;
  4357.  
  4358.     /*
  4359.      * The matching file names are stored in a growarray.  Init it empty.
  4360.      */
  4361.     ga_init(&ga);
  4362.     ga.ga_itemsize = sizeof(char_u *);
  4363.     ga.ga_growsize = 30;
  4364.  
  4365.     for (i = 0; i < num_pat; ++i)
  4366.     {
  4367.     /*
  4368.      * First expand environment variables, "~/" and "~user/".
  4369.      */
  4370.     p = pat[i];
  4371.     if (vim_strpbrk(p, (char_u *)"$~") != NULL)
  4372.     {
  4373.         p = expand_env_save(p);
  4374.         if (p == NULL)
  4375.         p = pat[i];
  4376.     }
  4377.  
  4378.     /*
  4379.      * If there are wildcards: Expand file names and add each match to the
  4380.      * list.  If there is no match, and EW_NOTFOUND is given, add the
  4381.      * pattern.
  4382.      * If there are no wildcards: Add the file name if it exists or when
  4383.      * EW_NOTFOUND is given.
  4384.      */
  4385.     if (mch_has_wildcard(p)
  4386.         ? (mch_expandpath(&ga, p, flags) == 0 && (flags & EW_NOTFOUND))
  4387.         : ((flags & EW_NOTFOUND) || mch_getperm(p) >= 0))
  4388.         addfile(&ga, p, flags);
  4389.  
  4390.     if (p != pat[i])
  4391.         vim_free(p);
  4392.     }
  4393.  
  4394.     *num_file = ga.ga_len;
  4395.     *file = (ga.ga_data != NULL) ? (char_u **)ga.ga_data : (char_u **)"";
  4396.  
  4397.     recursive = FALSE;
  4398.  
  4399.     return (ga.ga_data != NULL) ? OK : FAIL;
  4400. }
  4401.  
  4402. /*
  4403.  * Add a file to a file list.  Accepted flags:
  4404.  * EW_DIR    add directories.
  4405.  * EW_FILE    add files.
  4406.  * EW_NOTFOUND    add even when it doesn't exist.
  4407.  */
  4408.     void
  4409. addfile(gap, f, flags)
  4410.     struct growarray    *gap;
  4411.     char_u        *f;    /* filename */
  4412.     int            flags;
  4413. {
  4414.     char_u    *p;
  4415.     int        isdir;
  4416.  
  4417.     /* if the file/dir doesn't exist, may not add it */
  4418.     if (!(flags & EW_NOTFOUND) && mch_getperm(f) < 0)
  4419.     return;
  4420.  
  4421. #ifdef FNAME_ILLEGAL
  4422.     /* if the file/dir contains illegal characters, don't add it */
  4423.     if (vim_strpbrk(f, (char_u *)FNAME_ILLEGAL) != NULL)
  4424.     return;
  4425. #endif
  4426.  
  4427.     isdir = mch_isdir(f);
  4428.     if ((isdir && !(flags & EW_DIR)) || (!isdir && !(flags & EW_FILE)))
  4429.     return;
  4430.  
  4431.     /* Make room for another item in the file list. */
  4432.     if (ga_grow(gap, 1) == FAIL)
  4433.     return;
  4434.  
  4435.     p = alloc((unsigned)(STRLEN(f) + 1 + isdir));
  4436.     if (p == NULL)
  4437.     return;
  4438.  
  4439.     STRCPY(p, f);
  4440. #ifdef BACKSLASH_IN_FILENAME
  4441.     slash_adjust(p);
  4442. #endif
  4443.     /*
  4444.      * Append a slash or backslash after directory names.
  4445.      */
  4446. #ifndef DONT_ADD_PATHSEP_TO_DIR 
  4447.     if (isdir)
  4448.     STRCAT(p, PATHSEPSTR);
  4449. #endif
  4450.     ((char_u **)gap->ga_data)[gap->ga_len++] = p;
  4451.     --gap->ga_room;
  4452. }
  4453. #endif /* !NO_EXPANDPATH */
  4454.  
  4455. /*
  4456.  * Free the list of files returned by expand_wildcards() or other expansion
  4457.  * functions.
  4458.  */
  4459.     void
  4460. FreeWild(num, file)
  4461.     int        num;
  4462.     char_u  **file;
  4463. {
  4464.     if (file == NULL || num == 0)
  4465.     return;
  4466. #if defined(__EMX__) && defined(__ALWAYS_HAS_TRAILING_NULL_POINTER) /* XXX */
  4467.     /*
  4468.      * Is this still OK for when other functions than expand_wildcards() have
  4469.      * been used???
  4470.      */
  4471.     _fnexplodefree((char **)file);
  4472. #else
  4473.     while (num--)
  4474.     vim_free(file[num]);
  4475.     vim_free(file);
  4476. #endif
  4477. }
  4478.